diff --git a/TP/TP01/P01/dahuapp.js b/TP/TP01/P01/dahuapp.js new file mode 100644 index 0000000000000000000000000000000000000000..41c69e9169345a9a6703325d5557a4cc36913e19 --- /dev/null +++ b/TP/TP01/P01/dahuapp.js @@ -0,0 +1,880 @@ +"use strict"; + +/** + * Dahuapp core module. + * + * @param window window javascript object. + * @param $ jQuery + * @returns dahuapp core module. + */ +(function (window, $) { + var dahuapp = (function () { + + var self = {}; + + /* private API */ + + var DahuScreencastGenerator = function () { + + /* + * Format the specified string in a readable format. + */ + function htmlFormat(htmlString) { + var i; + var readableHTML = htmlString; + var lb = '\n'; + var htags = ["<html", "</html>", "</head>", "<title", "</title>", "<meta", "<link", "</body>"]; + for (i = 0; i < htags.length; ++i) { + var hhh = htags[i]; + readableHTML = readableHTML.replace(new RegExp(hhh, 'gi'), lb + hhh); + } + var btags = ["</div>", "</section>", "</span>", "<br>", "<br />", "<blockquote", "</blockquote>", "<ul", "</ul>", "<ol", "</ol>", "<li", "<\!--", "<script", "</script>"]; + for (i = 0; i < btags.length; ++i) { + var bbb = btags[i]; + readableHTML = readableHTML.replace(new RegExp(bbb, 'gi'), lb + bbb); + } + var ftags = ["<img", "<legend", "</legend>", "<button", "</button>"]; + for (i = 0; i < ftags.length; ++i) { + var fff = ftags[i]; + readableHTML = readableHTML.replace(new RegExp(fff, 'gi'), lb + fff); + } + var xtags = ["<body", "<head", "<div", "<section", "<span", "<p"]; + for (i = 0; i < xtags.length; ++i) { + var xxx = xtags[i]; + readableHTML = readableHTML.replace(new RegExp(xxx, 'gi'), lb + lb + xxx); + } + return readableHTML; + } + + /* + * Generates the html header. + */ + var generateHtmlHeader = function ($generated, cssGen) { + $('head', $generated) + .append($(document.createElement('title')) + .append("Dahu Presentation"))/* TODO: make this customizable */ + .append($(document.createElement('meta')) + .attr({'charset': 'utf-8'})) + .append($(document.createElement('script')) + .attr({'src': 'http://code.jquery.com/jquery-1.9.1.min.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'parse-search.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('link')) + .attr({'rel': 'stylesheet', 'href': 'dahuapp.viewer.css'})) + .append($(document.createElement('style')) + .append(cssGen)); + }; + + /* + * Generates the objects. + */ + + var generateHtmlBackgroundImage = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('img')) + .attr({'src': object.img, 'alt': object.img, 'class': 'background ' + object.id})); + }; + var generateHtmlTooltip = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'tooltip ' + object.id}) + .append(object.text)); + }; + + var generateCssTooltip = function ($generated, object) { + var style = []; + + if( object.color != null ) { + style.push('background-color: ' + object.color); + } + if( object.width != null ) { + style.push('width: ' + object.width); + } + + if( style.length != 0 ) { + $generated.append( + '.' + object.id + '{' + style.join(';') + '}\n'); + } + + return $generated; + }; + + /* + * Returns the code used to call the viewer to the presentation. + */ + var getBasicCallCode = function (jsonModel) { + var code = '(function($) {\n'; + code += ' var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams);\n'; + code += ' myPresentation.load(' + jsonModel + ');\n'; + code += ' myPresentation.start();\n'; + code += '})(jQuery);\n'; + return code; + }; + + /* + * Generates the html body. + */ + var generateHtmlBody = function ($generated, jsonModel, jsonGen) { + $('body', $generated) + /* We could use a <section> here too, but it does not work with MS IE 8. + Alternatively, adding this in the header would work: + + <!--[if lt IE 9]> + <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + */ + .append($(document.createElement('div')) + .attr({'id': 'my-dahu-presentation'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.viewer.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'type': 'text/javascript'}) + .append(getBasicCallCode(jsonGen))); + $('#my-dahu-presentation', $generated) + .append($(document.createElement('div')) + .attr({'id': 'loading'}).append("Loading presentation...")) + .append($(document.createElement('div')) + .attr({'class': 'object-list', + 'style': 'display: none'})) + .append($(document.createElement('div')) + .attr({'class': 'control'})); + + /* Adding the objects to the page */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "background": + generateHtmlBackgroundImage($generated, object); + break; + case "tooltip": + generateHtmlTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + /* Warning here, i'm not sure if $.each is always over, here */ + + /* Adding the control buttons to the page */ + $('.control', $generated) + .css({'top': (jsonModel.getImageHeight() + 16) + 'px'}) + .append($(document.createElement('button')) + .attr({'class': 'previous'}) + .append('Previous')) + .append($(document.createElement('button')) + .attr({'class': 'next'}) + .append('Next')); + + /* Adding the mouse cursor image */ + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'mouse-cursor'}) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor.png', 'alt': 'img/cursor.png', 'class': 'mouse-cursor-normal'})) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor-pause.png', 'alt': 'img/cursor-pause.png', + 'style': 'display: none', 'class': 'mouse-cursor-pause'}))); + }; + + /* + * Generates the css String with the Json model. + */ + this.generateCssString = function (jsonModel) { + var $generated = $('<style></style>'); + + /* Going through each object */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "tooltip": + generateCssTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + return $generated.text(); + } + + /* + * Generates the html String with the Json model. + */ + this.generateHtmlString = function (jsonModel, jsonGen, cssGen) { + /* Initialising the compilation area */ + var $generated = $(document.createElement('div')); + + /* We create the html using the json */ + $generated.append($(document.createElement('html')) + .attr({'lang': 'en'})); + $('html', $generated) + .append($(document.createElement('head'))) + .append($(document.createElement('body'))); + + generateHtmlHeader($generated, cssGen); + generateHtmlBody($generated, jsonModel, jsonGen); + + var result = htmlFormat($generated.html()); + + return '<!DOCTYPE html>\n' + result; + }; + + /* + * Generates the generated JSON using the JSONmodel. + * @param {object} jsonModel The json model to transform. + * @param {java.awt.Dimension} imgDim The dimension of images. + */ + this.generateJsonString = function (jsonModel, imgDim) { + var generated = self.createScreencastGeneratedModel(); + generated.setImageSize(imgDim.width, imgDim.height); + generated.setInitialBackground(jsonModel.getInitialBackground()); + generated.setInitialMousePos(jsonModel.getInitialMousePos()); + for (var i = 0; i < jsonModel.getNbSlide(); i++) { + var actionList = jsonModel.getActionList(i); + for (var j = 0; j < actionList.length; j++) { + /* + * We don't add the two first actions of the first slide + * because they are present in the presentation metadata. + * It corresponds to the mouse initial pos and first background. + */ + if (i > 0 || j > 1) { + generated.addAction(actionList[j], imgDim.width, imgDim.height); + } + } + } + return generated.getJson(); + }; + }; + + /* + * Model for a JSON object that will only be used by the viewer, never + * saved on a file, used to transform the properties of actions + * specified on the JSON file of a presentation to executable + * functions for each action. + */ + var DahuScreencastExecutableModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* + * Creates a functions representing the specified action, and adds + * it to this object. + * @param {object} action + */ + var addExecutableAction = function (action) { + var executableAction = { + 'id': action.id, + 'trigger': action.trigger, + 'target': action.target, + 'delayAfter': action.delayAfter, + 'doneFunction': function (events, selector) { + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.delayAfter); + } + }; + if (executableAction.delayAfter == null) { + executableAction.delayAfter = 200; + } + switch (action.type.toLowerCase()) { + case "appear": + executableAction.abs = (action.abs * json.metaData.imageWidth) + 'px'; + executableAction.ord = (action.ord * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(); + }; + break; + case "disappear": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + $(selector + ' .' + this.target).hide(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).show(); + }; + executableAction.executeImmediately = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + break; + case "move": + executableAction.finalAbs = (action.finalAbs * json.metaData.imageWidth) + 'px'; + executableAction.finalOrd = (action.finalOrd * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.speed = action.speed; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + if (this.duration == null) { + var initialAbsPix = this.initialAbs.replace('px', ''); + var initialOrdPix = this.initialOrd.replace('px', ''); + var finalAbsPix = this.finalAbs.replace('px', ''); + var finalOrdPix = this.finalOrd.replace('px', ''); + var distance = Math.sqrt(Math.pow(finalAbsPix - initialAbsPix, 2) + + Math.pow(finalOrdPix - initialOrdPix, 2)); + if (!this.speed) { + this.speed = .8; // in pixel per milisecond: fast, but not too much. + } + this.duration = distance + this.speed; + if (this.duration < 200) { // Slow down a bit for short distances. + this.duration = 200; + } + } + $(sel).animate({ + 'left': this.finalAbs, + 'top': this.finalOrd + }, this.duration, 'linear', function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).css({ + 'left': this.initialAbs, + 'top': this.initialOrd + }); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + $(sel).css({ + 'left': this.finalAbs, + 'top': this.finalOrd + }); + }; + break; + case "delay": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.duration); + }; + executableAction.executeReverse = function (selector) { + // Nothing! + }; + executableAction.executeImmediately = function (selector) { + // Nothing too! + }; + break; + } + json.action.push(executableAction); + }; + + /* Public API */ + + /* + * Loads the specified JSON read from a 'presentation.json' file, + * and stores the functions representing each actions in an object. + * @param {object} jsonToLoad + */ + this.loadJson = function (jsonToLoad) { + json.metaData = jsonToLoad.metaData; + for (var i = 0; i < jsonToLoad.action.length; i++) { + addExecutableAction(jsonToLoad.action[i]); + } + }; + + /* + * Returns the object containing the functions. + */ + this.getJson = function () { + return json; + }; + }; + + /* + * Used to transform the 'dahu' file to a JSON file used by the viewer, + * which only contains some metaData and a list of actions. + */ + var DahuScreencastGeneratedModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* Public API */ + + /* + * Returns a string representation of this json. + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * Setters for the generated json metadata. + */ + this.setImageSize = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + this.setInitialMousePos = function (pos) { + json.metaData.initialMouseX = pos.x; + json.metaData.initialMouseY = pos.y; + }; + + this.setInitialBackground = function (id) { + json.metaData.initialBackgroundId = id; + }; + + this.addAction = function (action) { + json.action.push(action); + }; + + /* + * Transforms a JSON containing action properties to a JSON containing + * the execution functions. + * @param {Object} json + * @returns {Object} A json object containing the execution functions + * for all the actions of the presentation. + */ + this.toExecutableList = function (json) { + var executableList = { + metaData: json.metaData, + action: new Array() + }; + for (var i = 0; i < json.action.length; i++) { + addExecutableAction(executableList, json.action[i]); + } + return executableList; + }; + }; + + /* + * Represents a 'dahu' file for a project. + */ + var DahuScreencastModel = function () { + + /* Private API */ + + var json = {}; + + /* + * Generates a unique action ID. + * + * With this implementation, this ID is unique as long as the user + * doesn't replace it manually with a not kind value or replace + * the nextUniqueId with bad intentions. + * But maybe that a UUID is a bit tiresome to put as an anchor... + */ + var generateUniqueActionId = function () { + json.metaData.nextUniqueId++; + return json.metaData.nextUniqueId.toString(); + }; + + /* + * This method checks if the json representing a dahu project is + * in the good version. It's in case a project file was created + * with a previous version of Dahu, and that some fields are + * missing. + * + * It doesn't control each field (at the moment) but only the + * fields that can be missing due to a new Dahu version and not + * to a manual editing. + * + * This method doesn't check any Json syntax or something like that. + */ + var upgradeJsonVersion = function () { + // Checks if unique IDs are in the project file + if (!json.metaData.nextUniqueId) { + var currentId = 0; + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].action.length; j++) { + json.data[i].action[j].id = currentId.toString(); + currentId++; + } + } + json.metaData.nextUniqueId = currentId; + } + }; + + /* Public API */ + + /* + * json variable generated from a JSON file. + * @param String stringJson String loaded from JSON file. + */ + this.loadJson = function (stringJson) { + json = JSON.parse(stringJson); + upgradeJsonVersion(); + }; + + /* + * Create a new presentation variable in the JSON file which will contain slides. + */ + this.createPresentation = function (width, height) { + json.metaData = {}; + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + json.metaData.nextUniqueId = 0; + json.data = new Array(); + }; + + /* + * Add a new slide in the presentation variable of the JSON file. + * @param int index wanted for the slide. + * @param String idSlide Unique identifier for the slide. + * @param String img Related to pathname of the image. + * @param double mouseX Abscissa mouse position in %. + * @param double mouseY Ordinate mouse position in %. + * @return Index of the newly added slide. + */ + this.addSlide = function (indexSlide, idSlide, img, mouseX, mouseY, speed) { + var slide = { + "object": new Array(), + "action": new Array() + }; + json.data.splice(indexSlide, 0, slide); + this.addObject(indexSlide, "background", idSlide, img); + this.addObject(indexSlide, "mouse"); + this.addAction(indexSlide, "move", json.data[indexSlide].object[1].id, "onClick", mouseX, mouseY, speed); + this.addAction(indexSlide, "appear", json.data[indexSlide].object[0].id, "afterPrevious"); + }; + + /* + * Object factory. + * Add a new Object in the slide idSlide. + * @param int idSlide + * @param string type + * Other params can be specified depending on the object's type. + */ + this.addObject = function (idSlide, type) { + var object = { + "type": type + }; + switch (type.toLowerCase()) { + case "background": + object.id = arguments[2] + json.data[idSlide].object.length; + object.img = arguments[3] || ""; + break; + case "mouse": + object.id = "mouse-cursor"; + break; + case "tooltip": + /* + * TODO: we'll need a more robust unique name + * when we start actually using this. + */ + object.id = "s" + idSlide + "-o" + json.data[idSlide].object.length; + object.text = arguments[2] || ""; + object.color = arguments[3] || null; + object.width = arguments[4] || ""; + json.data[idSlide].object.push(object); + var objectLength = json.data[idSlide].object.length; + var last = json.data[idSlide].object[objectLength-1]; + json.data[idSlide].object[objectLength-1] = + json.data[idSlide].object[objectLength-2]; + json.data[idSlide].object[objectLength-2] = last; + break; + } + if(type.toLowerCase() != "tooltip"){ + json.data[idSlide].object.push(object); + } + }; + + /* + * Action factory. + * Add a new Action in the slide idSlide whose target is the id of an object. + * Three types of trigger : "withPrevious", "afterPrevious", "onClick". + * @param int idSlide + * @param string type + * @param string target + * @param string trigger + * Other params can be specified depending on the object's type. + */ + this.addAction = function (idSlide, type, target, trigger) { + var action = { + "id": generateUniqueActionId(), + "type": type, + "target": target, + "trigger": trigger + }; + switch (type.toLowerCase()) { + case "appear": + action.abs = arguments[4] || 0.0; + action.ord = arguments[5] || 0.0; + action.duration = arguments[6] || 0; + break; + case "disappear": + action.duration = arguments[4] || 0; + break; + case "move": + action.finalAbs = arguments[4] || 0.0; + action.finalOrd = arguments[5] || 0.0; + action.speed = arguments[6] || 0; + break; + } + json.data[idSlide].action.push(action); + }; + + this.editMouse = function (idSlide, idAction, mouseX, mouseY) { + json.data[idSlide].action[idAction].finalAbs = mouseX; + json.data[idSlide].action[idAction].finalOrd = mouseY; + }; + + /* + * Sets a title for the presentation. + * @param String title Title to set. + */ + this.setTitle = function (title) { + json.metaData.title = title; + }; + + /* + * Sets an annotation for the presentation. + * @param String annotation Annotation to set. + */ + this.setAnnotation = function (annotation) { + json.metaData.annotation = annotation; + }; + + /* + * Inverts the two slides (their positions on the table). + * @param int idSlide1 Index of the first slide. + * @param int idSlide2 Index of the second slide. + */ + this.invertSlides = function (idSlide1, idSlide2) { + var tmp = json.data[idSlide1]; + json.data[idSlide1] = json.data[idSlide2]; + json.data[idSlide2] = tmp; + }; + + /* + * Inverts the two actions (their positions on the table). + * @param int idSlide + * @param int idAction1 + * @param int idAction2 + */ + this.invertActions = function (idSlide, idAction1, idAction2) { + var tmp = json.data[idSlide].action[idAction1]; + json.data[idSlide].action[idAction1] = json.data[idSlide].action[idAction2]; + json.data[idSlide].action[idAction2] = tmp; + }; + + /* + * Returns the actions on the specified slide. + * @returns {Array} + */ + this.getActionList = function (idSlide) { + return json.data[idSlide].action; + }; + + /* + * Catches all the objects of the presentation + * @returns {Array} List of objects of the presentation + */ + this.getObjectList = function () { + var objectList = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + var indexObject = 0; + while (json.data[indexSlide].object[indexObject]) { + objectList.push(json.data[indexSlide].object[indexObject]); + indexObject++; + } + indexSlide++; + } + return objectList; + }; + + /* + * Returns an array containing all the background images. + * @returns {Array} List of background images. + */ + this.getImageList = function () { + var list = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + list.push(json.data[indexSlide].object[0].img); + indexSlide++; + } + ; + return list; + }; + + /* + * Returns an object containing the id of the first background. + * @returns {string} Id of the first background. + */ + this.getInitialBackground = function () { + return json.data[0].object[0].id; + }; + + /* + * Returns an object containing the initial mouse position. + * @returns {object} Initial position of mouse. + */ + this.getInitialMousePos = function () { + var pos = {}; + pos.x = json.data[0].action[0].finalAbs; + pos.y = json.data[0].action[0].finalOrd; + return pos; + }; + + /* + * Removes the slide at the specified index. + * @param {int} idSlide + */ + this.removeSlide = function (idSlide) { + json.data.splice(idSlide, 1); + }; + + /* + * Removes the action at the specified slide. + * @param {int} idSlide + * @param {int} idAction + */ + this.removeAction = function (idSlide, idAction) { + json.data[idSlide].action.splice(idAction, 1); + }; + + /* + * Removes the specified object from the slide. + * Also removes all the actions attached to this object. + * @param {int} idSlide + * @param {int} idObject + */ + this.removeObject = function (idSlide, idObject) { + var removed = json.data[idSlide].object.splice(idObject, 1); + for (var i = 0; i < json.data.length; i++) { + var j = 0; + while (json.data[i].action[j]) { + if (json.data[i].action[j].target === removed.id) { + json.data[i].action.splice(j, 1); + } else { + j++; + } + } + } + }; + + /* + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * @returns {String} returns the index for the next slide. + */ + this.getNbSlide = function () { + return json.data.length; + }; + + /* + * @return {object} returns the object identified by idSlide + */ + this.getSlide = function (idSlide) { + return json.data[idSlide]; + }; + + /* + * Sets the size of images for the generated presentation. + * The parameters can be null : it means there are no + * requirement for this dimension. + * @param {int} width New width for the generated images. + * @param {int} height New height for the generated images. + */ + this.setImageSizeRequirements = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + /* + * Gets the width of images for the generated presentation. + * @return {int or null} Width of generated images. + */ + this.getImageWidth = function () { + return json.metaData.imageWidth; + }; + + /* + * Gets the height of images for the generated presentation. + * @return {int or null} Height of generated images. + */ + this.getImageHeight = function () { + return json.metaData.imageHeight; + }; + + /* + * Gets a background image (no one in particular, the first met). + * @return {string} The name of a background image. + */ + this.getABackgroundImage = function () { + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].object.length; j++) { + if (json.data[i].object[j].type === "background") { + return json.data[i].object[j].img; + } + } + } + return null; + }; + }; + + /* public API */ + + self.version = "0.0.1"; + + self.createScreencastGenerator = function createScreencastGenerator() { + return new DahuScreencastGenerator(); + }; + + self.createScreencastModel = function createScreencastModel() { + return new DahuScreencastModel(); + }; + + self.createScreencastExecutableModel = function createScreencastExecutableModel() { + return new DahuScreencastExecutableModel(); + }; + + self.createScreencastGeneratedModel = function createScreencastGeneratedModel() { + return new DahuScreencastGeneratedModel(); + }; + + return self; + })(); + + window.dahuapp = dahuapp; + +})(window, jQuery); \ No newline at end of file diff --git a/TP/TP01/P01/dahuapp.viewer.css b/TP/TP01/P01/dahuapp.viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ea934576dad6ca9263a6163de58f5fe4534d1f0b --- /dev/null +++ b/TP/TP01/P01/dahuapp.viewer.css @@ -0,0 +1,25 @@ +.object-list { + position: absolute; + margin: 0px; + padding: 0px; +} + +.mouse-cursor { + position: absolute; +} + +.control { + position: relative; +} + +.background { + position: absolute; +} + +.tooltip { + position: absolute; + width: 100px; + padding: 4px; + margin: 2px; + border: 2px black solid; +} \ No newline at end of file diff --git a/TP/TP01/P01/dahuapp.viewer.js b/TP/TP01/P01/dahuapp.viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..12ad03b2cdc503a8fd6ff3f5fdc2a74edbb36edb --- /dev/null +++ b/TP/TP01/P01/dahuapp.viewer.js @@ -0,0 +1,456 @@ +"use strict"; + +/** + * Dahuapp viewer module. + * + * @param dahuapp dahuapp object to augment with module. + * @param $ jQuery + * @returns dahuapp extended with viewer module. + */ + +(function(dahuapp, $) { + var viewer = (function() { + + var self = {}; + + var DahuViewerModel = function(select, getParams) { + + /* Private API */ + + var json = null; + var selector = select; + var parseAutoOption = function(name, defaultValue) { + var res = getParams[name]; + if (res == null) { + if (name == 'auto') { + return false; + } else { + return parseAutoOption('auto', defaultValue); + } + } + if (res.toLowerCase() === 'false') { + return false; + } + res = parseInt(res); + if (isNaN(res)) { + // e.g. ?autoplay or ?autoplay=true + return defaultValue; + } + return res; + } + + /* Whether to wait for "next" event between actions */ + var autoPlay = parseAutoOption('autoplay', 5000); + /* Whether to wait for "next" event on page load */ + var autoStart = parseAutoOption('autostart', 5000); + /* Whether to loop back to start at the end of presentation */ + var autoLoop = parseAutoOption('autoloop', 5000); + + var events = (function() { + var self = {}; + /* + * Creates a generic event. + */ + var createEvent = function() { + var callbacks = $.Callbacks(); + return { + publish: callbacks.fire, + subscribe: callbacks.add, + unsubscribe: callbacks.remove, + unsubscribeAll: callbacks.empty + }; + }; + /* + * Called when the button next is pressed. + */ + self.onNext = createEvent(); + /* + * Called when the button previous is pressed. + */ + self.onPrevious = createEvent(); + /* + * Called when an action is over. + */ + self.onActionOver = createEvent(); + /* + * Called when an action starts. + */ + self.onActionStart = createEvent(); + /* + * Called when at least one action was running and has finished. + */ + self.onAllActionFinish = createEvent(); + + return self; + })(); + + /* + * Variables used like index for methodes subscribed. + */ + var currentAction = 0; /* Action currently running */ + var nextAction = 0; /* Action to execute on 'Next' click */ + var nbActionsRunning = 0; + var previousAnchor = -1; /* Last entered anchor, only used in + * case the 'onhashchange' event is + * not supported by the web browser */ + + /* + * Functions to reinitialise running actions and subscribed + * callbacks (reinitialise is called once without stopping + * all the actions, so the two functions are separated). + */ + var stopAllActions = function() { + $(selector + " .object-list").children().stop(true, true); + reinitialiseCallbackLists(); + nbActionsRunning = 0; + }; + var reinitialiseCallbackLists = function() { + events.onActionStart.unsubscribeAll(); + events.onActionStart.subscribe(onActionStartEventHandler); + events.onAllActionFinish.unsubscribeAll(); + }; + + /* + * Timer used to program onNext event in autoplay mode. + */ + var playTimer = 0; + + /* + * Function used when an "onNextEvent" event is caught. + */ + var onNextEventHandler = function() { + /* + * If the user pressed "next" before an autoplay event + * is triggered, it replaces the autoplay event, hence + * cancels it: + */ + window.clearTimeout(playTimer); + + enterAnimationMode(); + stopAllActions(); + var tmpAction = nextAction; + var onlyWithPrevious = true; + nextAction++; + currentAction = nextAction; + while (json.action[currentAction] && onlyWithPrevious) { + switch (json.action[currentAction].trigger) { + case 'onClick': + nextAction = currentAction; + onlyWithPrevious = false; + break; + case 'withPrevious': + var tmp = currentAction; + /* + * We can't directly pass 'execute' as callback because we + * allow the 'execute' function to reference a property of the + * object (by using 'this.property') so we have to call the + * function in the containing object to make that available + */ + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + while (json.action[nextAction] && json.action[nextAction].trigger !== 'onClick') { + nextAction++; + } + onlyWithPrevious = false; + break; + } + currentAction++; + } + if (json.action[tmpAction]) { + launch(json.action[tmpAction]); + } + if (nextAction > json.action.length) { + nextAction = json.action.length; + } + }; + + /* + * Function used when an "onPreviousEvent" event is caught. + */ + var onPreviousEventHandler = function() { + stopAllActions(); + currentAction = nextAction - 1; + while (json.action[currentAction] && json.action[currentAction].trigger !== 'onClick') { + launchReverse(json.action[currentAction]); + currentAction--; + } + /* currentAction = -1 means that it's the beginning */ + if (currentAction > -1) { + launchReverse(json.action[currentAction]); + } + if (currentAction < 0) { + currentAction = 0; + } + nextAction = currentAction; + }; + + /* + * Function used when an "onActionOverEvent" event is caught. + */ + var onActionOverEventHandler = function() { + nbActionsRunning--; + if (nbActionsRunning === 0) { + events.onAllActionFinish.publish(events, selector); + reinitialiseCallbackLists(); + while (json.action[currentAction]) { + switch (json.action[currentAction].trigger) { + case 'onClick': + leaveAnimationMode(); + if (autoPlay && nbActionsRunning === 0) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoPlay); + } + return; + case 'withPrevious': + var tmp = currentAction; + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + currentAction++; + return; + } + currentAction++; + + } + if (autoLoop && nbActionsRunning === 0) { + setTimeout(function () { + resetPresentation(); + startPresentationMaybe(); + }, autoLoop); + } + } + leaveAnimationMode(); + }; + + /* + * Function used when an "onActionStartEvent" event is caught. + */ + var onActionStartEventHandler = function() { + nbActionsRunning++; + }; + + /* + * Enter and leave "animation" mode. The viewer is in + * animation mode when something is going on without human + * interaction (i.e. executing actions before the next + * "onClick"). + */ + var enterAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').hide(); + $(selector + ' .mouse-cursor-normal').show(); + }; + + var leaveAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').show(); + $(selector + ' .mouse-cursor-normal').hide(); + }; + + /* + * Function used to perform actions. + */ + var launch = function(action) { + action.execute(events, selector); + }; + var launchReverse = function(action) { + action.executeReverse(selector); + }; + + /* + * The two following methods each returns an array containing the + * actions to execute to reach the given anchor (respectively + * forward or backwards). + * + * If the given anchor matches none of the actions, then an empty + * array is returned. + */ + var getActionsToJumpForward = function(anchor) { + var actions = new Array(); + for (var i = nextAction; i < json.action.length; i++) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + if (json.action[i].id == anchor) { + return actions; + } else { + actions.push(json.action[i]); + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + var getActionsToJumpBackwards = function(anchor) { + var actions = new Array(); + for (var i = nextAction - 1; i >= 0; i--) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + actions.push(json.action[i]); + if (json.action[i].id == anchor) { + return actions; + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + + /* + * Updates the position of the presentation depending on the + * given anchor (next action wanted). + */ + var jumpToAnchor = function(anchor) { + if (anchor !== '') { + stopAllActions(); + if (anchor > nextAction) { + // forward + var actions = getActionsToJumpForward(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeImmediately(selector); + } + nextAction += actions.length; + } else { + // backwards + var actions = getActionsToJumpBackwards(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeReverse(selector); + } + nextAction -= actions.length; + } + } + }; + + var resetPresentation = function() { + window.clearTimeout(playTimer); + + currentAction = 0; + nextAction = 0; + nbActionsRunning = 0; + + /* + * At the beginning, the visible image is the first one of the presentation + */ + $(selector + " .object-list").children().hide(); + + $(selector + " ." + json.metaData.initialBackgroundId).show(); + + $(selector + " .mouse-cursor").css({ + 'top': (json.metaData.initialMouseY * json.metaData.imageHeight) + "px", + 'left': (json.metaData.initialMouseX * json.metaData.imageWidth) + "px" + }); + + $(selector + " .mouse-cursor").show(); + } + + var startPresentationMaybe = function() { + if (autoStart) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoStart); + } + } + + /* Public API */ + + this.loadUrl = function(url) { + var dataJson; + $.ajax({ + 'async': false, + 'global': false, + 'url': url, + 'dataType': "json", + 'success': function(data) { + dataJson = data; + } + }); + + load(dataJson); + }; + + this.load = function(dataJson) { + /* Transforms data JSON to executable functions for actions */ + var execModel = dahuapp.createScreencastExecutableModel(); + execModel.loadJson(dataJson); + json = execModel.getJson(); + }; + + this.start = function() { + + /* + * Subscription of methods to their events. + */ + events.onNext.subscribe(onNextEventHandler); + events.onPrevious.subscribe(onPreviousEventHandler); + events.onActionOver.subscribe(onActionOverEventHandler); + events.onActionStart.subscribe(onActionStartEventHandler); + + resetPresentation(); + + /* + * If an anchor has been specified, we place the presentation + * in the right position. + */ + jumpToAnchor(window.location.hash.substring(1)); + + /* + * If the anchor changes during the presentation, then the + * presentation is updated + */ + if ("onhashchange" in window) { + // event supported + window.onhashchange = function () { + jumpToAnchor(window.location.hash.substring(1)); + }; + } else { + // event not supported : periodical check + window.setInterval(function () { + if (window.location.hash.substring(1) !== previousAnchor) { + previousAnchor = window.location.hash.substring(1); + jumpToAnchor(window.location.hash.substring(1)); + } + }, 100); + } + + /* + * A click on the "next" button publishes a nextSlide event + */ + $(selector + " .next").click(function() { + events.onNext.publish(); + }); + + /* + * A click on the "previous" button publishes a previousSlide event + */ + $(selector + " .previous").click(function() { + events.onPrevious.publish(); + }); + + /* + * Everything is ready, show the presentation + * (hidden with style="display: none" from HTML). + */ + $("#loading").hide(); + $(selector + " .object-list").show(); + startPresentationMaybe(); + }; + }; + + self.createDahuViewer = function(selector, getParams) { + return new DahuViewerModel(selector, getParams); + }; + + return self; + })(); + + dahuapp.viewer = viewer; +})(dahuapp || {}, jQuery); diff --git a/TP/TP01/P01/img/04821769-3cf8-3d93-1512-390866bc0347.png b/TP/TP01/P01/img/04821769-3cf8-3d93-1512-390866bc0347.png new file mode 100644 index 0000000000000000000000000000000000000000..638585ccbe338871616610bac3e6126333a49ca5 Binary files /dev/null and b/TP/TP01/P01/img/04821769-3cf8-3d93-1512-390866bc0347.png differ diff --git a/TP/TP01/P01/img/38164498-3401-469c-2d51-be0716f10da6.png b/TP/TP01/P01/img/38164498-3401-469c-2d51-be0716f10da6.png new file mode 100644 index 0000000000000000000000000000000000000000..9ae61b6ea710fb8f446e13fc59bbe16febe24ff3 Binary files /dev/null and b/TP/TP01/P01/img/38164498-3401-469c-2d51-be0716f10da6.png differ diff --git a/TP/TP01/P01/img/474855e6-20f7-77f4-1868-0dba1ebf98f3.png b/TP/TP01/P01/img/474855e6-20f7-77f4-1868-0dba1ebf98f3.png new file mode 100644 index 0000000000000000000000000000000000000000..9bc0da30a4dc38c1061bfe2fc177bc412a556dd3 Binary files /dev/null and b/TP/TP01/P01/img/474855e6-20f7-77f4-1868-0dba1ebf98f3.png differ diff --git a/TP/TP01/P01/img/4e3c77eb-c2c2-46ed-31d5-e4f233330135.png b/TP/TP01/P01/img/4e3c77eb-c2c2-46ed-31d5-e4f233330135.png new file mode 100644 index 0000000000000000000000000000000000000000..748fa1ed0aa6bfcfdd4a5d673037fb86eb4509b9 Binary files /dev/null and b/TP/TP01/P01/img/4e3c77eb-c2c2-46ed-31d5-e4f233330135.png differ diff --git a/TP/TP01/P01/img/78f85c35-2c9b-3a8b-24e8-e6fce4becebd.png b/TP/TP01/P01/img/78f85c35-2c9b-3a8b-24e8-e6fce4becebd.png new file mode 100644 index 0000000000000000000000000000000000000000..2b37c2a413fbb88036f6c5144bb8554e1c9563c8 Binary files /dev/null and b/TP/TP01/P01/img/78f85c35-2c9b-3a8b-24e8-e6fce4becebd.png differ diff --git a/TP/TP01/P01/img/7beb5165-3202-df48-c03b-507674983fce.png b/TP/TP01/P01/img/7beb5165-3202-df48-c03b-507674983fce.png new file mode 100644 index 0000000000000000000000000000000000000000..81b3b7681a25b9c4db17fd8d0010d532755a0dde Binary files /dev/null and b/TP/TP01/P01/img/7beb5165-3202-df48-c03b-507674983fce.png differ diff --git a/TP/TP01/P01/img/a30bf35e-dffb-6d60-d1dd-32bf5a9e9be2.png b/TP/TP01/P01/img/a30bf35e-dffb-6d60-d1dd-32bf5a9e9be2.png new file mode 100644 index 0000000000000000000000000000000000000000..ece2cd5d966d8a7e82a34e91e79686900997be26 Binary files /dev/null and b/TP/TP01/P01/img/a30bf35e-dffb-6d60-d1dd-32bf5a9e9be2.png differ diff --git a/TP/TP01/P01/img/bdfa5054-0bc1-d7be-5906-15afa7ed845a.png b/TP/TP01/P01/img/bdfa5054-0bc1-d7be-5906-15afa7ed845a.png new file mode 100644 index 0000000000000000000000000000000000000000..57d10a733db5d4b140e16a1f4a80b9cfc827eafb Binary files /dev/null and b/TP/TP01/P01/img/bdfa5054-0bc1-d7be-5906-15afa7ed845a.png differ diff --git a/TP/TP01/P01/img/cc0bda09-26de-1127-e7fb-f8c52fb215a7.png b/TP/TP01/P01/img/cc0bda09-26de-1127-e7fb-f8c52fb215a7.png new file mode 100644 index 0000000000000000000000000000000000000000..521e7c84a0e8faf1bf398337c57135eaee5deb03 Binary files /dev/null and b/TP/TP01/P01/img/cc0bda09-26de-1127-e7fb-f8c52fb215a7.png differ diff --git a/TP/TP01/P01/img/cursor-pause.png b/TP/TP01/P01/img/cursor-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9c93cc142f4326a188eafc3c0fe96f2975dcab0c Binary files /dev/null and b/TP/TP01/P01/img/cursor-pause.png differ diff --git a/TP/TP01/P01/img/cursor.png b/TP/TP01/P01/img/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..5b4a20e63078ce18bb11a4e601a1994b261522ef Binary files /dev/null and b/TP/TP01/P01/img/cursor.png differ diff --git a/TP/TP01/P01/img/d32cc79e-d5bc-5af1-2e81-c555a9ac549e.png b/TP/TP01/P01/img/d32cc79e-d5bc-5af1-2e81-c555a9ac549e.png new file mode 100644 index 0000000000000000000000000000000000000000..fea2ec88722c84a5cdfaf3b602621bec8e84ac80 Binary files /dev/null and b/TP/TP01/P01/img/d32cc79e-d5bc-5af1-2e81-c555a9ac549e.png differ diff --git a/TP/TP01/P01/img/e3ab3ff3-9c0e-b7c9-6ebe-9b724e0b4020.png b/TP/TP01/P01/img/e3ab3ff3-9c0e-b7c9-6ebe-9b724e0b4020.png new file mode 100644 index 0000000000000000000000000000000000000000..562d1f827f222ad0d464bb30fae72614b3a9dc33 Binary files /dev/null and b/TP/TP01/P01/img/e3ab3ff3-9c0e-b7c9-6ebe-9b724e0b4020.png differ diff --git a/TP/TP01/P01/img/f94c5951-79d1-3d55-ce8b-e7de32fab48d.png b/TP/TP01/P01/img/f94c5951-79d1-3d55-ce8b-e7de32fab48d.png new file mode 100644 index 0000000000000000000000000000000000000000..7f8f6e212789a4b95fd0d65cbf09d76a0ec36c69 Binary files /dev/null and b/TP/TP01/P01/img/f94c5951-79d1-3d55-ce8b-e7de32fab48d.png differ diff --git a/TP/TP01/P01/index.html b/TP/TP01/P01/index.html new file mode 100644 index 0000000000000000000000000000000000000000..329efc825ad6bd6db7ba9920b8a3fcf67b0f8ba0 --- /dev/null +++ b/TP/TP01/P01/index.html @@ -0,0 +1,427 @@ +<!DOCTYPE html> + +<html lang="en"> + +<head> +<title>Dahu Presentation +</title> +<meta charset="utf-8"> +<script src="http://code.jquery.com/jquery-1.9.1.min.js" type="text/javascript"> +</script> +<script src="parse-search.js" type="text/javascript"> +</script> + +<link rel="stylesheet" href="dahuapp.viewer.css"><style>.s0-o2{background-color: #FFFFDD;width: 240px} +.s1-o2{background-color: #FFFFDD;width: 240px} +.s2-o2{background-color: #FFFFDD;width: 240px} +.s3-o2{background-color: #FFFFDD;width: 240px} +.s4-o2{background-color: #FFFFDD;width: 240px} +.s5-o2{background-color: #FFFFDD;width: 240px} +.s6-o2{background-color: #FFFFDD;width: 240px} +.s7-o2{background-color: #FFFFDD;width: 240px} +.s8-o2{background-color: #FFFFDD;width: 240px} +.s9-o2{background-color: #FFFFDD;width: 240px} +.s10-o2{background-color: #FFFFDD;width: 240px} +.s11-o2{background-color: #FFFFDD;width: 240px} +</style> +</head> + +<body> + +<div id="my-dahu-presentation"> + +<div id="loading">Loading presentation... +</div> + +<div class="object-list" style="display: none"> +<img src="img/78f85c35-2c9b-3a8b-24e8-e6fce4becebd.png" alt="img/78f85c35-2c9b-3a8b-24e8-e6fce4becebd.png" class="background 78f85c35-2c9b-3a8b-24e8-e6fce4becebd0"> + +<div class="tooltip s0-o2">Démarrer l'application MatLab avec la commande usuelle. Vérifier qu'il s'agit d'une version supérieure à 2012a. +</div> +<img src="img/e3ab3ff3-9c0e-b7c9-6ebe-9b724e0b4020.png" alt="img/e3ab3ff3-9c0e-b7c9-6ebe-9b724e0b4020.png" class="background e3ab3ff3-9c0e-b7c9-6ebe-9b724e0b40200"> + +<div class="tooltip s1-o2">Créer un modèle Simulink depuis le menu New et l'entrée Simulink Model. +</div> +<img src="img/4e3c77eb-c2c2-46ed-31d5-e4f233330135.png" alt="img/4e3c77eb-c2c2-46ed-31d5-e4f233330135.png" class="background 4e3c77eb-c2c2-46ed-31d5-e4f2333301350"> + +<div class="tooltip s2-o2">Voici un modèle Simulink vide. +</div> +<img src="img/d32cc79e-d5bc-5af1-2e81-c555a9ac549e.png" alt="img/d32cc79e-d5bc-5af1-2e81-c555a9ac549e.png" class="background d32cc79e-d5bc-5af1-2e81-c555a9ac549e0"> + +<div class="tooltip s3-o2">Ouvrir la boite à outils Simulink. +</div> +<img src="img/f94c5951-79d1-3d55-ce8b-e7de32fab48d.png" alt="img/f94c5951-79d1-3d55-ce8b-e7de32fab48d.png" class="background f94c5951-79d1-3d55-ce8b-e7de32fab48d0"> + +<div class="tooltip s4-o2">Ouvrir l'onglet Source. +</div> +<img src="img/38164498-3401-469c-2d51-be0716f10da6.png" alt="img/38164498-3401-469c-2d51-be0716f10da6.png" class="background 38164498-3401-469c-2d51-be0716f10da60"> + +<div class="tooltip s5-o2">Sélectionner le bloc Générateur de Sinusoïde. +</div> +<img src="img/a30bf35e-dffb-6d60-d1dd-32bf5a9e9be2.png" alt="img/a30bf35e-dffb-6d60-d1dd-32bf5a9e9be2.png" class="background a30bf35e-dffb-6d60-d1dd-32bf5a9e9be20"> + +<div class="tooltip s6-o2">Déposer un bloc Générateur de Sinusoïde dans votre modèle. +</div> +<img src="img/cc0bda09-26de-1127-e7fb-f8c52fb215a7.png" alt="img/cc0bda09-26de-1127-e7fb-f8c52fb215a7.png" class="background cc0bda09-26de-1127-e7fb-f8c52fb215a70"> + +<div class="tooltip s7-o2">Ouvrir l'onglet Sink (puit de données). +</div> +<img src="img/bdfa5054-0bc1-d7be-5906-15afa7ed845a.png" alt="img/bdfa5054-0bc1-d7be-5906-15afa7ed845a.png" class="background bdfa5054-0bc1-d7be-5906-15afa7ed845a0"> + +<div class="tooltip s8-o2">Sélectionner le bloc Oscilloscope. +</div> +<img src="img/474855e6-20f7-77f4-1868-0dba1ebf98f3.png" alt="img/474855e6-20f7-77f4-1868-0dba1ebf98f3.png" class="background 474855e6-20f7-77f4-1868-0dba1ebf98f30"> + +<div class="tooltip s9-o2">Déposer un bloc Oscilloscope dans votre modèle. +</div> +<img src="img/04821769-3cf8-3d93-1512-390866bc0347.png" alt="img/04821769-3cf8-3d93-1512-390866bc0347.png" class="background 04821769-3cf8-3d93-1512-390866bc03470"> + +<div class="tooltip s10-o2">Connecter l'entrée du bloc Oscilloscope avec la sortie du bloc Générateur de Sinusoïde. +</div> +<img src="img/7beb5165-3202-df48-c03b-507674983fce.png" alt="img/7beb5165-3202-df48-c03b-507674983fce.png" class="background 7beb5165-3202-df48-c03b-507674983fce0"> + +<div class="tooltip s11-o2">Sauvegarder votre modèle. +</div> + +<div class="mouse-cursor"> +<img src="img/cursor.png" alt="img/cursor.png" class="mouse-cursor-normal"> +<img src="img/cursor-pause.png" alt="img/cursor-pause.png" style="display: none" class="mouse-cursor-pause"> +</div> +</div> + +<div class="control" style="top: 616px;"> +<button class="previous">Previous +</button> +<button class="next">Next +</button> +</div> +</div> +<script src="dahuapp.js" type="text/javascript"> +</script> +<script src="dahuapp.viewer.js" type="text/javascript"> +</script> +<script type="text/javascript">(function($) { + var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams); + myPresentation.load({ + "metaData": { + "imageWidth": 800, + "imageHeight": 600, + "initialBackgroundId": "78f85c35-2c9b-3a8b-24e8-e6fce4becebd0", + "initialMouseX": 0.33541666666666664, + "initialMouseY": 0.4444444444444444 + }, + "action": [ + { + "id": "25", + "type": "appear", + "target": "s0-o2", + "trigger": "afterPrevious", + "abs": 0.305, + "ord": 0.1625, + "duration": 400 + }, + { + "id": "3", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.06666666666666667, + "finalOrd": 0.4766666666666667, + "speed": 0.8 + }, + { + "id": "4", + "type": "appear", + "target": "e3ab3ff3-9c0e-b7c9-6ebe-9b724e0b40200", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "26", + "type": "appear", + "target": "s1-o2", + "trigger": "afterPrevious", + "abs": 0.17666666666666667, + "ord": 0.1525, + "duration": 400 + }, + { + "id": "5", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.23333333333333334, + "finalOrd": 0.29444444444444445, + "speed": 0.8 + }, + { + "id": "6", + "type": "appear", + "target": "4e3c77eb-c2c2-46ed-31d5-e4f2333301350", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "27", + "type": "appear", + "target": "s2-o2", + "trigger": "afterPrevious", + "abs": 0.25, + "ord": 0.1575, + "duration": 400 + }, + { + "id": "7", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.175, + "finalOrd": 0.09666666666666666, + "speed": 0.8 + }, + { + "id": "8", + "type": "appear", + "target": "d32cc79e-d5bc-5af1-2e81-c555a9ac549e0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "28", + "type": "appear", + "target": "s3-o2", + "trigger": "afterPrevious", + "abs": 0.2, + "ord": 0.0875, + "duration": 400 + }, + { + "id": "9", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.8951388888888889, + "finalOrd": 0.4888888888888889, + "speed": 0.8 + }, + { + "id": "10", + "type": "appear", + "target": "f94c5951-79d1-3d55-ce8b-e7de32fab48d0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "29", + "type": "appear", + "target": "s4-o2", + "trigger": "afterPrevious", + "abs": 0.42, + "ord": 0.26375, + "duration": 400 + }, + { + "id": "11", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.7805555555555556, + "finalOrd": 0.6944444444444444, + "speed": 0.8 + }, + { + "id": "12", + "type": "appear", + "target": "38164498-3401-469c-2d51-be0716f10da60", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "30", + "type": "appear", + "target": "s5-o2", + "trigger": "afterPrevious", + "abs": 0.34833333333333333, + "ord": 0.32125, + "duration": 400 + }, + { + "id": "13", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.19027777777777777, + "finalOrd": 0.26, + "speed": 0.8 + }, + { + "id": "14", + "type": "appear", + "target": "a30bf35e-dffb-6d60-d1dd-32bf5a9e9be20", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "31", + "type": "appear", + "target": "s6-o2", + "trigger": "afterPrevious", + "abs": 0.165, + "ord": 0.1475, + "duration": 400 + }, + { + "id": "15", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.6513888888888889, + "finalOrd": 0.4033333333333333, + "speed": 0.8 + }, + { + "id": "16", + "type": "appear", + "target": "cc0bda09-26de-1127-e7fb-f8c52fb215a70", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "33", + "type": "appear", + "target": "s7-o2", + "trigger": "afterPrevious", + "abs": 0.38666666666666666, + "ord": 0.19625, + "duration": 400 + }, + { + "id": "17", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.9, + "finalOrd": 0.21666666666666667, + "speed": 0.8 + }, + { + "id": "18", + "type": "appear", + "target": "bdfa5054-0bc1-d7be-5906-15afa7ed845a0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "32", + "type": "appear", + "target": "s8-o2", + "trigger": "afterPrevious", + "abs": 0.3516666666666667, + "ord": 0.2725, + "duration": 400 + }, + { + "id": "19", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.31666666666666665, + "finalOrd": 0.2611111111111111, + "speed": 0.8 + }, + { + "id": "20", + "type": "appear", + "target": "474855e6-20f7-77f4-1868-0dba1ebf98f30", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "34", + "type": "appear", + "target": "s9-o2", + "trigger": "afterPrevious", + "abs": 0.10833333333333334, + "ord": 0.15, + "duration": 400 + }, + { + "id": "21", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.20347222222222222, + "finalOrd": 0.26666666666666666, + "speed": 0.8 + }, + { + "id": "22", + "type": "appear", + "target": "04821769-3cf8-3d93-1512-390866bc03470", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "35", + "type": "appear", + "target": "s10-o2", + "trigger": "afterPrevious", + "abs": 0.17, + "ord": 0.14625, + "duration": 400 + }, + { + "id": "23", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.03819444444444445, + "finalOrd": 0.16666666666666666, + "speed": 0.8 + }, + { + "id": "24", + "type": "appear", + "target": "7beb5165-3202-df48-c03b-507674983fce0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "36", + "type": "appear", + "target": "s11-o2", + "trigger": "afterPrevious", + "abs": 0.195, + "ord": 0.145, + "duration": 400 + } + ] +}); + myPresentation.start(); +})(jQuery); + +</script> +</body> +</html> \ No newline at end of file diff --git a/TP/TP01/P01/parse-search.js b/TP/TP01/P01/parse-search.js new file mode 100644 index 0000000000000000000000000000000000000000..e7d01c07f6a5d45b9fcabd5d271a8c6cfc5f00e2 --- /dev/null +++ b/TP/TP01/P01/parse-search.js @@ -0,0 +1,14 @@ +// Adapted from http://stackoverflow.com/questions/3234125/creating-array-from-window-location-hash +(function () { + var search = window.location.search.slice(1); + var array = search.split("&"); + + var values, form_data = {}; + + for (var i = 0; i < array.length; i += 1) { + values = array[i].split("="); + form_data[values[0]] = unescape(values[1]); + } + window.getParams = form_data; +}()) + diff --git a/TP/TP01/P02/dahuapp.js b/TP/TP01/P02/dahuapp.js new file mode 100644 index 0000000000000000000000000000000000000000..41c69e9169345a9a6703325d5557a4cc36913e19 --- /dev/null +++ b/TP/TP01/P02/dahuapp.js @@ -0,0 +1,880 @@ +"use strict"; + +/** + * Dahuapp core module. + * + * @param window window javascript object. + * @param $ jQuery + * @returns dahuapp core module. + */ +(function (window, $) { + var dahuapp = (function () { + + var self = {}; + + /* private API */ + + var DahuScreencastGenerator = function () { + + /* + * Format the specified string in a readable format. + */ + function htmlFormat(htmlString) { + var i; + var readableHTML = htmlString; + var lb = '\n'; + var htags = ["<html", "</html>", "</head>", "<title", "</title>", "<meta", "<link", "</body>"]; + for (i = 0; i < htags.length; ++i) { + var hhh = htags[i]; + readableHTML = readableHTML.replace(new RegExp(hhh, 'gi'), lb + hhh); + } + var btags = ["</div>", "</section>", "</span>", "<br>", "<br />", "<blockquote", "</blockquote>", "<ul", "</ul>", "<ol", "</ol>", "<li", "<\!--", "<script", "</script>"]; + for (i = 0; i < btags.length; ++i) { + var bbb = btags[i]; + readableHTML = readableHTML.replace(new RegExp(bbb, 'gi'), lb + bbb); + } + var ftags = ["<img", "<legend", "</legend>", "<button", "</button>"]; + for (i = 0; i < ftags.length; ++i) { + var fff = ftags[i]; + readableHTML = readableHTML.replace(new RegExp(fff, 'gi'), lb + fff); + } + var xtags = ["<body", "<head", "<div", "<section", "<span", "<p"]; + for (i = 0; i < xtags.length; ++i) { + var xxx = xtags[i]; + readableHTML = readableHTML.replace(new RegExp(xxx, 'gi'), lb + lb + xxx); + } + return readableHTML; + } + + /* + * Generates the html header. + */ + var generateHtmlHeader = function ($generated, cssGen) { + $('head', $generated) + .append($(document.createElement('title')) + .append("Dahu Presentation"))/* TODO: make this customizable */ + .append($(document.createElement('meta')) + .attr({'charset': 'utf-8'})) + .append($(document.createElement('script')) + .attr({'src': 'http://code.jquery.com/jquery-1.9.1.min.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'parse-search.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('link')) + .attr({'rel': 'stylesheet', 'href': 'dahuapp.viewer.css'})) + .append($(document.createElement('style')) + .append(cssGen)); + }; + + /* + * Generates the objects. + */ + + var generateHtmlBackgroundImage = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('img')) + .attr({'src': object.img, 'alt': object.img, 'class': 'background ' + object.id})); + }; + var generateHtmlTooltip = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'tooltip ' + object.id}) + .append(object.text)); + }; + + var generateCssTooltip = function ($generated, object) { + var style = []; + + if( object.color != null ) { + style.push('background-color: ' + object.color); + } + if( object.width != null ) { + style.push('width: ' + object.width); + } + + if( style.length != 0 ) { + $generated.append( + '.' + object.id + '{' + style.join(';') + '}\n'); + } + + return $generated; + }; + + /* + * Returns the code used to call the viewer to the presentation. + */ + var getBasicCallCode = function (jsonModel) { + var code = '(function($) {\n'; + code += ' var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams);\n'; + code += ' myPresentation.load(' + jsonModel + ');\n'; + code += ' myPresentation.start();\n'; + code += '})(jQuery);\n'; + return code; + }; + + /* + * Generates the html body. + */ + var generateHtmlBody = function ($generated, jsonModel, jsonGen) { + $('body', $generated) + /* We could use a <section> here too, but it does not work with MS IE 8. + Alternatively, adding this in the header would work: + + <!--[if lt IE 9]> + <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + */ + .append($(document.createElement('div')) + .attr({'id': 'my-dahu-presentation'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.viewer.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'type': 'text/javascript'}) + .append(getBasicCallCode(jsonGen))); + $('#my-dahu-presentation', $generated) + .append($(document.createElement('div')) + .attr({'id': 'loading'}).append("Loading presentation...")) + .append($(document.createElement('div')) + .attr({'class': 'object-list', + 'style': 'display: none'})) + .append($(document.createElement('div')) + .attr({'class': 'control'})); + + /* Adding the objects to the page */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "background": + generateHtmlBackgroundImage($generated, object); + break; + case "tooltip": + generateHtmlTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + /* Warning here, i'm not sure if $.each is always over, here */ + + /* Adding the control buttons to the page */ + $('.control', $generated) + .css({'top': (jsonModel.getImageHeight() + 16) + 'px'}) + .append($(document.createElement('button')) + .attr({'class': 'previous'}) + .append('Previous')) + .append($(document.createElement('button')) + .attr({'class': 'next'}) + .append('Next')); + + /* Adding the mouse cursor image */ + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'mouse-cursor'}) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor.png', 'alt': 'img/cursor.png', 'class': 'mouse-cursor-normal'})) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor-pause.png', 'alt': 'img/cursor-pause.png', + 'style': 'display: none', 'class': 'mouse-cursor-pause'}))); + }; + + /* + * Generates the css String with the Json model. + */ + this.generateCssString = function (jsonModel) { + var $generated = $('<style></style>'); + + /* Going through each object */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "tooltip": + generateCssTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + return $generated.text(); + } + + /* + * Generates the html String with the Json model. + */ + this.generateHtmlString = function (jsonModel, jsonGen, cssGen) { + /* Initialising the compilation area */ + var $generated = $(document.createElement('div')); + + /* We create the html using the json */ + $generated.append($(document.createElement('html')) + .attr({'lang': 'en'})); + $('html', $generated) + .append($(document.createElement('head'))) + .append($(document.createElement('body'))); + + generateHtmlHeader($generated, cssGen); + generateHtmlBody($generated, jsonModel, jsonGen); + + var result = htmlFormat($generated.html()); + + return '<!DOCTYPE html>\n' + result; + }; + + /* + * Generates the generated JSON using the JSONmodel. + * @param {object} jsonModel The json model to transform. + * @param {java.awt.Dimension} imgDim The dimension of images. + */ + this.generateJsonString = function (jsonModel, imgDim) { + var generated = self.createScreencastGeneratedModel(); + generated.setImageSize(imgDim.width, imgDim.height); + generated.setInitialBackground(jsonModel.getInitialBackground()); + generated.setInitialMousePos(jsonModel.getInitialMousePos()); + for (var i = 0; i < jsonModel.getNbSlide(); i++) { + var actionList = jsonModel.getActionList(i); + for (var j = 0; j < actionList.length; j++) { + /* + * We don't add the two first actions of the first slide + * because they are present in the presentation metadata. + * It corresponds to the mouse initial pos and first background. + */ + if (i > 0 || j > 1) { + generated.addAction(actionList[j], imgDim.width, imgDim.height); + } + } + } + return generated.getJson(); + }; + }; + + /* + * Model for a JSON object that will only be used by the viewer, never + * saved on a file, used to transform the properties of actions + * specified on the JSON file of a presentation to executable + * functions for each action. + */ + var DahuScreencastExecutableModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* + * Creates a functions representing the specified action, and adds + * it to this object. + * @param {object} action + */ + var addExecutableAction = function (action) { + var executableAction = { + 'id': action.id, + 'trigger': action.trigger, + 'target': action.target, + 'delayAfter': action.delayAfter, + 'doneFunction': function (events, selector) { + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.delayAfter); + } + }; + if (executableAction.delayAfter == null) { + executableAction.delayAfter = 200; + } + switch (action.type.toLowerCase()) { + case "appear": + executableAction.abs = (action.abs * json.metaData.imageWidth) + 'px'; + executableAction.ord = (action.ord * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(); + }; + break; + case "disappear": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + $(selector + ' .' + this.target).hide(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).show(); + }; + executableAction.executeImmediately = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + break; + case "move": + executableAction.finalAbs = (action.finalAbs * json.metaData.imageWidth) + 'px'; + executableAction.finalOrd = (action.finalOrd * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.speed = action.speed; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + if (this.duration == null) { + var initialAbsPix = this.initialAbs.replace('px', ''); + var initialOrdPix = this.initialOrd.replace('px', ''); + var finalAbsPix = this.finalAbs.replace('px', ''); + var finalOrdPix = this.finalOrd.replace('px', ''); + var distance = Math.sqrt(Math.pow(finalAbsPix - initialAbsPix, 2) + + Math.pow(finalOrdPix - initialOrdPix, 2)); + if (!this.speed) { + this.speed = .8; // in pixel per milisecond: fast, but not too much. + } + this.duration = distance + this.speed; + if (this.duration < 200) { // Slow down a bit for short distances. + this.duration = 200; + } + } + $(sel).animate({ + 'left': this.finalAbs, + 'top': this.finalOrd + }, this.duration, 'linear', function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).css({ + 'left': this.initialAbs, + 'top': this.initialOrd + }); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + $(sel).css({ + 'left': this.finalAbs, + 'top': this.finalOrd + }); + }; + break; + case "delay": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.duration); + }; + executableAction.executeReverse = function (selector) { + // Nothing! + }; + executableAction.executeImmediately = function (selector) { + // Nothing too! + }; + break; + } + json.action.push(executableAction); + }; + + /* Public API */ + + /* + * Loads the specified JSON read from a 'presentation.json' file, + * and stores the functions representing each actions in an object. + * @param {object} jsonToLoad + */ + this.loadJson = function (jsonToLoad) { + json.metaData = jsonToLoad.metaData; + for (var i = 0; i < jsonToLoad.action.length; i++) { + addExecutableAction(jsonToLoad.action[i]); + } + }; + + /* + * Returns the object containing the functions. + */ + this.getJson = function () { + return json; + }; + }; + + /* + * Used to transform the 'dahu' file to a JSON file used by the viewer, + * which only contains some metaData and a list of actions. + */ + var DahuScreencastGeneratedModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* Public API */ + + /* + * Returns a string representation of this json. + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * Setters for the generated json metadata. + */ + this.setImageSize = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + this.setInitialMousePos = function (pos) { + json.metaData.initialMouseX = pos.x; + json.metaData.initialMouseY = pos.y; + }; + + this.setInitialBackground = function (id) { + json.metaData.initialBackgroundId = id; + }; + + this.addAction = function (action) { + json.action.push(action); + }; + + /* + * Transforms a JSON containing action properties to a JSON containing + * the execution functions. + * @param {Object} json + * @returns {Object} A json object containing the execution functions + * for all the actions of the presentation. + */ + this.toExecutableList = function (json) { + var executableList = { + metaData: json.metaData, + action: new Array() + }; + for (var i = 0; i < json.action.length; i++) { + addExecutableAction(executableList, json.action[i]); + } + return executableList; + }; + }; + + /* + * Represents a 'dahu' file for a project. + */ + var DahuScreencastModel = function () { + + /* Private API */ + + var json = {}; + + /* + * Generates a unique action ID. + * + * With this implementation, this ID is unique as long as the user + * doesn't replace it manually with a not kind value or replace + * the nextUniqueId with bad intentions. + * But maybe that a UUID is a bit tiresome to put as an anchor... + */ + var generateUniqueActionId = function () { + json.metaData.nextUniqueId++; + return json.metaData.nextUniqueId.toString(); + }; + + /* + * This method checks if the json representing a dahu project is + * in the good version. It's in case a project file was created + * with a previous version of Dahu, and that some fields are + * missing. + * + * It doesn't control each field (at the moment) but only the + * fields that can be missing due to a new Dahu version and not + * to a manual editing. + * + * This method doesn't check any Json syntax or something like that. + */ + var upgradeJsonVersion = function () { + // Checks if unique IDs are in the project file + if (!json.metaData.nextUniqueId) { + var currentId = 0; + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].action.length; j++) { + json.data[i].action[j].id = currentId.toString(); + currentId++; + } + } + json.metaData.nextUniqueId = currentId; + } + }; + + /* Public API */ + + /* + * json variable generated from a JSON file. + * @param String stringJson String loaded from JSON file. + */ + this.loadJson = function (stringJson) { + json = JSON.parse(stringJson); + upgradeJsonVersion(); + }; + + /* + * Create a new presentation variable in the JSON file which will contain slides. + */ + this.createPresentation = function (width, height) { + json.metaData = {}; + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + json.metaData.nextUniqueId = 0; + json.data = new Array(); + }; + + /* + * Add a new slide in the presentation variable of the JSON file. + * @param int index wanted for the slide. + * @param String idSlide Unique identifier for the slide. + * @param String img Related to pathname of the image. + * @param double mouseX Abscissa mouse position in %. + * @param double mouseY Ordinate mouse position in %. + * @return Index of the newly added slide. + */ + this.addSlide = function (indexSlide, idSlide, img, mouseX, mouseY, speed) { + var slide = { + "object": new Array(), + "action": new Array() + }; + json.data.splice(indexSlide, 0, slide); + this.addObject(indexSlide, "background", idSlide, img); + this.addObject(indexSlide, "mouse"); + this.addAction(indexSlide, "move", json.data[indexSlide].object[1].id, "onClick", mouseX, mouseY, speed); + this.addAction(indexSlide, "appear", json.data[indexSlide].object[0].id, "afterPrevious"); + }; + + /* + * Object factory. + * Add a new Object in the slide idSlide. + * @param int idSlide + * @param string type + * Other params can be specified depending on the object's type. + */ + this.addObject = function (idSlide, type) { + var object = { + "type": type + }; + switch (type.toLowerCase()) { + case "background": + object.id = arguments[2] + json.data[idSlide].object.length; + object.img = arguments[3] || ""; + break; + case "mouse": + object.id = "mouse-cursor"; + break; + case "tooltip": + /* + * TODO: we'll need a more robust unique name + * when we start actually using this. + */ + object.id = "s" + idSlide + "-o" + json.data[idSlide].object.length; + object.text = arguments[2] || ""; + object.color = arguments[3] || null; + object.width = arguments[4] || ""; + json.data[idSlide].object.push(object); + var objectLength = json.data[idSlide].object.length; + var last = json.data[idSlide].object[objectLength-1]; + json.data[idSlide].object[objectLength-1] = + json.data[idSlide].object[objectLength-2]; + json.data[idSlide].object[objectLength-2] = last; + break; + } + if(type.toLowerCase() != "tooltip"){ + json.data[idSlide].object.push(object); + } + }; + + /* + * Action factory. + * Add a new Action in the slide idSlide whose target is the id of an object. + * Three types of trigger : "withPrevious", "afterPrevious", "onClick". + * @param int idSlide + * @param string type + * @param string target + * @param string trigger + * Other params can be specified depending on the object's type. + */ + this.addAction = function (idSlide, type, target, trigger) { + var action = { + "id": generateUniqueActionId(), + "type": type, + "target": target, + "trigger": trigger + }; + switch (type.toLowerCase()) { + case "appear": + action.abs = arguments[4] || 0.0; + action.ord = arguments[5] || 0.0; + action.duration = arguments[6] || 0; + break; + case "disappear": + action.duration = arguments[4] || 0; + break; + case "move": + action.finalAbs = arguments[4] || 0.0; + action.finalOrd = arguments[5] || 0.0; + action.speed = arguments[6] || 0; + break; + } + json.data[idSlide].action.push(action); + }; + + this.editMouse = function (idSlide, idAction, mouseX, mouseY) { + json.data[idSlide].action[idAction].finalAbs = mouseX; + json.data[idSlide].action[idAction].finalOrd = mouseY; + }; + + /* + * Sets a title for the presentation. + * @param String title Title to set. + */ + this.setTitle = function (title) { + json.metaData.title = title; + }; + + /* + * Sets an annotation for the presentation. + * @param String annotation Annotation to set. + */ + this.setAnnotation = function (annotation) { + json.metaData.annotation = annotation; + }; + + /* + * Inverts the two slides (their positions on the table). + * @param int idSlide1 Index of the first slide. + * @param int idSlide2 Index of the second slide. + */ + this.invertSlides = function (idSlide1, idSlide2) { + var tmp = json.data[idSlide1]; + json.data[idSlide1] = json.data[idSlide2]; + json.data[idSlide2] = tmp; + }; + + /* + * Inverts the two actions (their positions on the table). + * @param int idSlide + * @param int idAction1 + * @param int idAction2 + */ + this.invertActions = function (idSlide, idAction1, idAction2) { + var tmp = json.data[idSlide].action[idAction1]; + json.data[idSlide].action[idAction1] = json.data[idSlide].action[idAction2]; + json.data[idSlide].action[idAction2] = tmp; + }; + + /* + * Returns the actions on the specified slide. + * @returns {Array} + */ + this.getActionList = function (idSlide) { + return json.data[idSlide].action; + }; + + /* + * Catches all the objects of the presentation + * @returns {Array} List of objects of the presentation + */ + this.getObjectList = function () { + var objectList = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + var indexObject = 0; + while (json.data[indexSlide].object[indexObject]) { + objectList.push(json.data[indexSlide].object[indexObject]); + indexObject++; + } + indexSlide++; + } + return objectList; + }; + + /* + * Returns an array containing all the background images. + * @returns {Array} List of background images. + */ + this.getImageList = function () { + var list = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + list.push(json.data[indexSlide].object[0].img); + indexSlide++; + } + ; + return list; + }; + + /* + * Returns an object containing the id of the first background. + * @returns {string} Id of the first background. + */ + this.getInitialBackground = function () { + return json.data[0].object[0].id; + }; + + /* + * Returns an object containing the initial mouse position. + * @returns {object} Initial position of mouse. + */ + this.getInitialMousePos = function () { + var pos = {}; + pos.x = json.data[0].action[0].finalAbs; + pos.y = json.data[0].action[0].finalOrd; + return pos; + }; + + /* + * Removes the slide at the specified index. + * @param {int} idSlide + */ + this.removeSlide = function (idSlide) { + json.data.splice(idSlide, 1); + }; + + /* + * Removes the action at the specified slide. + * @param {int} idSlide + * @param {int} idAction + */ + this.removeAction = function (idSlide, idAction) { + json.data[idSlide].action.splice(idAction, 1); + }; + + /* + * Removes the specified object from the slide. + * Also removes all the actions attached to this object. + * @param {int} idSlide + * @param {int} idObject + */ + this.removeObject = function (idSlide, idObject) { + var removed = json.data[idSlide].object.splice(idObject, 1); + for (var i = 0; i < json.data.length; i++) { + var j = 0; + while (json.data[i].action[j]) { + if (json.data[i].action[j].target === removed.id) { + json.data[i].action.splice(j, 1); + } else { + j++; + } + } + } + }; + + /* + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * @returns {String} returns the index for the next slide. + */ + this.getNbSlide = function () { + return json.data.length; + }; + + /* + * @return {object} returns the object identified by idSlide + */ + this.getSlide = function (idSlide) { + return json.data[idSlide]; + }; + + /* + * Sets the size of images for the generated presentation. + * The parameters can be null : it means there are no + * requirement for this dimension. + * @param {int} width New width for the generated images. + * @param {int} height New height for the generated images. + */ + this.setImageSizeRequirements = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + /* + * Gets the width of images for the generated presentation. + * @return {int or null} Width of generated images. + */ + this.getImageWidth = function () { + return json.metaData.imageWidth; + }; + + /* + * Gets the height of images for the generated presentation. + * @return {int or null} Height of generated images. + */ + this.getImageHeight = function () { + return json.metaData.imageHeight; + }; + + /* + * Gets a background image (no one in particular, the first met). + * @return {string} The name of a background image. + */ + this.getABackgroundImage = function () { + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].object.length; j++) { + if (json.data[i].object[j].type === "background") { + return json.data[i].object[j].img; + } + } + } + return null; + }; + }; + + /* public API */ + + self.version = "0.0.1"; + + self.createScreencastGenerator = function createScreencastGenerator() { + return new DahuScreencastGenerator(); + }; + + self.createScreencastModel = function createScreencastModel() { + return new DahuScreencastModel(); + }; + + self.createScreencastExecutableModel = function createScreencastExecutableModel() { + return new DahuScreencastExecutableModel(); + }; + + self.createScreencastGeneratedModel = function createScreencastGeneratedModel() { + return new DahuScreencastGeneratedModel(); + }; + + return self; + })(); + + window.dahuapp = dahuapp; + +})(window, jQuery); \ No newline at end of file diff --git a/TP/TP01/P02/dahuapp.viewer.css b/TP/TP01/P02/dahuapp.viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ea934576dad6ca9263a6163de58f5fe4534d1f0b --- /dev/null +++ b/TP/TP01/P02/dahuapp.viewer.css @@ -0,0 +1,25 @@ +.object-list { + position: absolute; + margin: 0px; + padding: 0px; +} + +.mouse-cursor { + position: absolute; +} + +.control { + position: relative; +} + +.background { + position: absolute; +} + +.tooltip { + position: absolute; + width: 100px; + padding: 4px; + margin: 2px; + border: 2px black solid; +} \ No newline at end of file diff --git a/TP/TP01/P02/dahuapp.viewer.js b/TP/TP01/P02/dahuapp.viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..12ad03b2cdc503a8fd6ff3f5fdc2a74edbb36edb --- /dev/null +++ b/TP/TP01/P02/dahuapp.viewer.js @@ -0,0 +1,456 @@ +"use strict"; + +/** + * Dahuapp viewer module. + * + * @param dahuapp dahuapp object to augment with module. + * @param $ jQuery + * @returns dahuapp extended with viewer module. + */ + +(function(dahuapp, $) { + var viewer = (function() { + + var self = {}; + + var DahuViewerModel = function(select, getParams) { + + /* Private API */ + + var json = null; + var selector = select; + var parseAutoOption = function(name, defaultValue) { + var res = getParams[name]; + if (res == null) { + if (name == 'auto') { + return false; + } else { + return parseAutoOption('auto', defaultValue); + } + } + if (res.toLowerCase() === 'false') { + return false; + } + res = parseInt(res); + if (isNaN(res)) { + // e.g. ?autoplay or ?autoplay=true + return defaultValue; + } + return res; + } + + /* Whether to wait for "next" event between actions */ + var autoPlay = parseAutoOption('autoplay', 5000); + /* Whether to wait for "next" event on page load */ + var autoStart = parseAutoOption('autostart', 5000); + /* Whether to loop back to start at the end of presentation */ + var autoLoop = parseAutoOption('autoloop', 5000); + + var events = (function() { + var self = {}; + /* + * Creates a generic event. + */ + var createEvent = function() { + var callbacks = $.Callbacks(); + return { + publish: callbacks.fire, + subscribe: callbacks.add, + unsubscribe: callbacks.remove, + unsubscribeAll: callbacks.empty + }; + }; + /* + * Called when the button next is pressed. + */ + self.onNext = createEvent(); + /* + * Called when the button previous is pressed. + */ + self.onPrevious = createEvent(); + /* + * Called when an action is over. + */ + self.onActionOver = createEvent(); + /* + * Called when an action starts. + */ + self.onActionStart = createEvent(); + /* + * Called when at least one action was running and has finished. + */ + self.onAllActionFinish = createEvent(); + + return self; + })(); + + /* + * Variables used like index for methodes subscribed. + */ + var currentAction = 0; /* Action currently running */ + var nextAction = 0; /* Action to execute on 'Next' click */ + var nbActionsRunning = 0; + var previousAnchor = -1; /* Last entered anchor, only used in + * case the 'onhashchange' event is + * not supported by the web browser */ + + /* + * Functions to reinitialise running actions and subscribed + * callbacks (reinitialise is called once without stopping + * all the actions, so the two functions are separated). + */ + var stopAllActions = function() { + $(selector + " .object-list").children().stop(true, true); + reinitialiseCallbackLists(); + nbActionsRunning = 0; + }; + var reinitialiseCallbackLists = function() { + events.onActionStart.unsubscribeAll(); + events.onActionStart.subscribe(onActionStartEventHandler); + events.onAllActionFinish.unsubscribeAll(); + }; + + /* + * Timer used to program onNext event in autoplay mode. + */ + var playTimer = 0; + + /* + * Function used when an "onNextEvent" event is caught. + */ + var onNextEventHandler = function() { + /* + * If the user pressed "next" before an autoplay event + * is triggered, it replaces the autoplay event, hence + * cancels it: + */ + window.clearTimeout(playTimer); + + enterAnimationMode(); + stopAllActions(); + var tmpAction = nextAction; + var onlyWithPrevious = true; + nextAction++; + currentAction = nextAction; + while (json.action[currentAction] && onlyWithPrevious) { + switch (json.action[currentAction].trigger) { + case 'onClick': + nextAction = currentAction; + onlyWithPrevious = false; + break; + case 'withPrevious': + var tmp = currentAction; + /* + * We can't directly pass 'execute' as callback because we + * allow the 'execute' function to reference a property of the + * object (by using 'this.property') so we have to call the + * function in the containing object to make that available + */ + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + while (json.action[nextAction] && json.action[nextAction].trigger !== 'onClick') { + nextAction++; + } + onlyWithPrevious = false; + break; + } + currentAction++; + } + if (json.action[tmpAction]) { + launch(json.action[tmpAction]); + } + if (nextAction > json.action.length) { + nextAction = json.action.length; + } + }; + + /* + * Function used when an "onPreviousEvent" event is caught. + */ + var onPreviousEventHandler = function() { + stopAllActions(); + currentAction = nextAction - 1; + while (json.action[currentAction] && json.action[currentAction].trigger !== 'onClick') { + launchReverse(json.action[currentAction]); + currentAction--; + } + /* currentAction = -1 means that it's the beginning */ + if (currentAction > -1) { + launchReverse(json.action[currentAction]); + } + if (currentAction < 0) { + currentAction = 0; + } + nextAction = currentAction; + }; + + /* + * Function used when an "onActionOverEvent" event is caught. + */ + var onActionOverEventHandler = function() { + nbActionsRunning--; + if (nbActionsRunning === 0) { + events.onAllActionFinish.publish(events, selector); + reinitialiseCallbackLists(); + while (json.action[currentAction]) { + switch (json.action[currentAction].trigger) { + case 'onClick': + leaveAnimationMode(); + if (autoPlay && nbActionsRunning === 0) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoPlay); + } + return; + case 'withPrevious': + var tmp = currentAction; + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + currentAction++; + return; + } + currentAction++; + + } + if (autoLoop && nbActionsRunning === 0) { + setTimeout(function () { + resetPresentation(); + startPresentationMaybe(); + }, autoLoop); + } + } + leaveAnimationMode(); + }; + + /* + * Function used when an "onActionStartEvent" event is caught. + */ + var onActionStartEventHandler = function() { + nbActionsRunning++; + }; + + /* + * Enter and leave "animation" mode. The viewer is in + * animation mode when something is going on without human + * interaction (i.e. executing actions before the next + * "onClick"). + */ + var enterAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').hide(); + $(selector + ' .mouse-cursor-normal').show(); + }; + + var leaveAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').show(); + $(selector + ' .mouse-cursor-normal').hide(); + }; + + /* + * Function used to perform actions. + */ + var launch = function(action) { + action.execute(events, selector); + }; + var launchReverse = function(action) { + action.executeReverse(selector); + }; + + /* + * The two following methods each returns an array containing the + * actions to execute to reach the given anchor (respectively + * forward or backwards). + * + * If the given anchor matches none of the actions, then an empty + * array is returned. + */ + var getActionsToJumpForward = function(anchor) { + var actions = new Array(); + for (var i = nextAction; i < json.action.length; i++) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + if (json.action[i].id == anchor) { + return actions; + } else { + actions.push(json.action[i]); + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + var getActionsToJumpBackwards = function(anchor) { + var actions = new Array(); + for (var i = nextAction - 1; i >= 0; i--) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + actions.push(json.action[i]); + if (json.action[i].id == anchor) { + return actions; + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + + /* + * Updates the position of the presentation depending on the + * given anchor (next action wanted). + */ + var jumpToAnchor = function(anchor) { + if (anchor !== '') { + stopAllActions(); + if (anchor > nextAction) { + // forward + var actions = getActionsToJumpForward(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeImmediately(selector); + } + nextAction += actions.length; + } else { + // backwards + var actions = getActionsToJumpBackwards(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeReverse(selector); + } + nextAction -= actions.length; + } + } + }; + + var resetPresentation = function() { + window.clearTimeout(playTimer); + + currentAction = 0; + nextAction = 0; + nbActionsRunning = 0; + + /* + * At the beginning, the visible image is the first one of the presentation + */ + $(selector + " .object-list").children().hide(); + + $(selector + " ." + json.metaData.initialBackgroundId).show(); + + $(selector + " .mouse-cursor").css({ + 'top': (json.metaData.initialMouseY * json.metaData.imageHeight) + "px", + 'left': (json.metaData.initialMouseX * json.metaData.imageWidth) + "px" + }); + + $(selector + " .mouse-cursor").show(); + } + + var startPresentationMaybe = function() { + if (autoStart) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoStart); + } + } + + /* Public API */ + + this.loadUrl = function(url) { + var dataJson; + $.ajax({ + 'async': false, + 'global': false, + 'url': url, + 'dataType': "json", + 'success': function(data) { + dataJson = data; + } + }); + + load(dataJson); + }; + + this.load = function(dataJson) { + /* Transforms data JSON to executable functions for actions */ + var execModel = dahuapp.createScreencastExecutableModel(); + execModel.loadJson(dataJson); + json = execModel.getJson(); + }; + + this.start = function() { + + /* + * Subscription of methods to their events. + */ + events.onNext.subscribe(onNextEventHandler); + events.onPrevious.subscribe(onPreviousEventHandler); + events.onActionOver.subscribe(onActionOverEventHandler); + events.onActionStart.subscribe(onActionStartEventHandler); + + resetPresentation(); + + /* + * If an anchor has been specified, we place the presentation + * in the right position. + */ + jumpToAnchor(window.location.hash.substring(1)); + + /* + * If the anchor changes during the presentation, then the + * presentation is updated + */ + if ("onhashchange" in window) { + // event supported + window.onhashchange = function () { + jumpToAnchor(window.location.hash.substring(1)); + }; + } else { + // event not supported : periodical check + window.setInterval(function () { + if (window.location.hash.substring(1) !== previousAnchor) { + previousAnchor = window.location.hash.substring(1); + jumpToAnchor(window.location.hash.substring(1)); + } + }, 100); + } + + /* + * A click on the "next" button publishes a nextSlide event + */ + $(selector + " .next").click(function() { + events.onNext.publish(); + }); + + /* + * A click on the "previous" button publishes a previousSlide event + */ + $(selector + " .previous").click(function() { + events.onPrevious.publish(); + }); + + /* + * Everything is ready, show the presentation + * (hidden with style="display: none" from HTML). + */ + $("#loading").hide(); + $(selector + " .object-list").show(); + startPresentationMaybe(); + }; + }; + + self.createDahuViewer = function(selector, getParams) { + return new DahuViewerModel(selector, getParams); + }; + + return self; + })(); + + dahuapp.viewer = viewer; +})(dahuapp || {}, jQuery); diff --git a/TP/TP01/P02/img/0c3cede8-b8ad-467d-2057-2a73747a585f.png b/TP/TP01/P02/img/0c3cede8-b8ad-467d-2057-2a73747a585f.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b62c8590b52c579a210545fcb22eee8c640e8f Binary files /dev/null and b/TP/TP01/P02/img/0c3cede8-b8ad-467d-2057-2a73747a585f.png differ diff --git a/TP/TP01/P02/img/16f02396-3c95-ab6a-c7af-c6e6aa4c708a.png b/TP/TP01/P02/img/16f02396-3c95-ab6a-c7af-c6e6aa4c708a.png new file mode 100644 index 0000000000000000000000000000000000000000..ec340a9b4ac81609b87d295dc5cb8561aef93c63 Binary files /dev/null and b/TP/TP01/P02/img/16f02396-3c95-ab6a-c7af-c6e6aa4c708a.png differ diff --git a/TP/TP01/P02/img/1895ad3f-8322-65f5-cc85-a730ee6a9102.png b/TP/TP01/P02/img/1895ad3f-8322-65f5-cc85-a730ee6a9102.png new file mode 100644 index 0000000000000000000000000000000000000000..f1111b244e6dd6f23827824bf964550efddb0ff7 Binary files /dev/null and b/TP/TP01/P02/img/1895ad3f-8322-65f5-cc85-a730ee6a9102.png differ diff --git a/TP/TP01/P02/img/21b4ef3c-3d71-77be-69e4-b4afe30311f5.png b/TP/TP01/P02/img/21b4ef3c-3d71-77be-69e4-b4afe30311f5.png new file mode 100644 index 0000000000000000000000000000000000000000..449ce2b6fd11233e65607372f8e70effdb0c141c Binary files /dev/null and b/TP/TP01/P02/img/21b4ef3c-3d71-77be-69e4-b4afe30311f5.png differ diff --git a/TP/TP01/P02/img/3f6a7fc7-c0ae-d0e6-416c-9164a0311aa4.png b/TP/TP01/P02/img/3f6a7fc7-c0ae-d0e6-416c-9164a0311aa4.png new file mode 100644 index 0000000000000000000000000000000000000000..1ba5b0a67ed6c3d190519d43a51959a8957a8080 Binary files /dev/null and b/TP/TP01/P02/img/3f6a7fc7-c0ae-d0e6-416c-9164a0311aa4.png differ diff --git a/TP/TP01/P02/img/47b1d9d8-377e-8956-12e0-1a5855936ad9.png b/TP/TP01/P02/img/47b1d9d8-377e-8956-12e0-1a5855936ad9.png new file mode 100644 index 0000000000000000000000000000000000000000..a089ae943dbb760b33af4a965f4682750fe8a148 Binary files /dev/null and b/TP/TP01/P02/img/47b1d9d8-377e-8956-12e0-1a5855936ad9.png differ diff --git a/TP/TP01/P02/img/4cd13680-2e47-849f-6779-e9f8967d51b8.png b/TP/TP01/P02/img/4cd13680-2e47-849f-6779-e9f8967d51b8.png new file mode 100644 index 0000000000000000000000000000000000000000..531f221177c07e44686c378afaf7a9fa42d1d9bd Binary files /dev/null and b/TP/TP01/P02/img/4cd13680-2e47-849f-6779-e9f8967d51b8.png differ diff --git a/TP/TP01/P02/img/551c31b6-7df8-0500-8bc8-55e8283c8ca9.png b/TP/TP01/P02/img/551c31b6-7df8-0500-8bc8-55e8283c8ca9.png new file mode 100644 index 0000000000000000000000000000000000000000..643034c4a5bcde90936851c6bdd6643a5ab04090 Binary files /dev/null and b/TP/TP01/P02/img/551c31b6-7df8-0500-8bc8-55e8283c8ca9.png differ diff --git a/TP/TP01/P02/img/5cc446dc-d0c1-0797-7b20-7b193c939258.png b/TP/TP01/P02/img/5cc446dc-d0c1-0797-7b20-7b193c939258.png new file mode 100644 index 0000000000000000000000000000000000000000..2c5ace1513edf3ad66c44e6a2d5d74c5b3938f04 Binary files /dev/null and b/TP/TP01/P02/img/5cc446dc-d0c1-0797-7b20-7b193c939258.png differ diff --git a/TP/TP01/P02/img/6ad4fffd-1771-3264-ee1b-f257b1b545fc.png b/TP/TP01/P02/img/6ad4fffd-1771-3264-ee1b-f257b1b545fc.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b62c8590b52c579a210545fcb22eee8c640e8f Binary files /dev/null and b/TP/TP01/P02/img/6ad4fffd-1771-3264-ee1b-f257b1b545fc.png differ diff --git a/TP/TP01/P02/img/88d9520b-2d83-1911-c07c-adc370f752ad.png b/TP/TP01/P02/img/88d9520b-2d83-1911-c07c-adc370f752ad.png new file mode 100644 index 0000000000000000000000000000000000000000..19ef410489368434daa56b7fcc630e592ad13d2b Binary files /dev/null and b/TP/TP01/P02/img/88d9520b-2d83-1911-c07c-adc370f752ad.png differ diff --git a/TP/TP01/P02/img/99e6c70e-5d6f-796d-d931-04aef1b87fe2.png b/TP/TP01/P02/img/99e6c70e-5d6f-796d-d931-04aef1b87fe2.png new file mode 100644 index 0000000000000000000000000000000000000000..850b51e32f25d775ff8d32207bd4246265fae6ab Binary files /dev/null and b/TP/TP01/P02/img/99e6c70e-5d6f-796d-d931-04aef1b87fe2.png differ diff --git a/TP/TP01/P02/img/9ebb6e2b-6fd7-b953-582b-c32f016bc519.png b/TP/TP01/P02/img/9ebb6e2b-6fd7-b953-582b-c32f016bc519.png new file mode 100644 index 0000000000000000000000000000000000000000..38e07ec599176a6eb32f7b6f6815dbac74d67a83 Binary files /dev/null and b/TP/TP01/P02/img/9ebb6e2b-6fd7-b953-582b-c32f016bc519.png differ diff --git a/TP/TP01/P02/img/9f513610-b961-16aa-61b5-06227f763eb4.png b/TP/TP01/P02/img/9f513610-b961-16aa-61b5-06227f763eb4.png new file mode 100644 index 0000000000000000000000000000000000000000..81c4e5c535a67ef94b23422328cd52875c23db0a Binary files /dev/null and b/TP/TP01/P02/img/9f513610-b961-16aa-61b5-06227f763eb4.png differ diff --git a/TP/TP01/P02/img/a83c11e4-e0c1-7255-ab82-a769973581eb.png b/TP/TP01/P02/img/a83c11e4-e0c1-7255-ab82-a769973581eb.png new file mode 100644 index 0000000000000000000000000000000000000000..226a9218c0bf7dcd22789f3129b9e8b5a3d89d44 Binary files /dev/null and b/TP/TP01/P02/img/a83c11e4-e0c1-7255-ab82-a769973581eb.png differ diff --git a/TP/TP01/P02/img/a8a2a39c-ff74-dc5b-d479-61864f684c7a.png b/TP/TP01/P02/img/a8a2a39c-ff74-dc5b-d479-61864f684c7a.png new file mode 100644 index 0000000000000000000000000000000000000000..4d152d35e2bcc34193f241bcf86f3f502e51cd75 Binary files /dev/null and b/TP/TP01/P02/img/a8a2a39c-ff74-dc5b-d479-61864f684c7a.png differ diff --git a/TP/TP01/P02/img/cafbe82e-d416-c25c-87cd-1822187ecc57.png b/TP/TP01/P02/img/cafbe82e-d416-c25c-87cd-1822187ecc57.png new file mode 100644 index 0000000000000000000000000000000000000000..951b6ebad107b2569aec2ac87977ff3bbbf2ff10 Binary files /dev/null and b/TP/TP01/P02/img/cafbe82e-d416-c25c-87cd-1822187ecc57.png differ diff --git a/TP/TP01/P02/img/cb1dac10-3623-e6b5-6b6c-39560bd09319.png b/TP/TP01/P02/img/cb1dac10-3623-e6b5-6b6c-39560bd09319.png new file mode 100644 index 0000000000000000000000000000000000000000..0ad370f944dda0692683ba7d8460fba62b45b870 Binary files /dev/null and b/TP/TP01/P02/img/cb1dac10-3623-e6b5-6b6c-39560bd09319.png differ diff --git a/TP/TP01/P02/img/cf7e765a-2ea5-10ec-9a89-50717ef4e657.png b/TP/TP01/P02/img/cf7e765a-2ea5-10ec-9a89-50717ef4e657.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b62c8590b52c579a210545fcb22eee8c640e8f Binary files /dev/null and b/TP/TP01/P02/img/cf7e765a-2ea5-10ec-9a89-50717ef4e657.png differ diff --git a/TP/TP01/P02/img/cursor-pause.png b/TP/TP01/P02/img/cursor-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9c93cc142f4326a188eafc3c0fe96f2975dcab0c Binary files /dev/null and b/TP/TP01/P02/img/cursor-pause.png differ diff --git a/TP/TP01/P02/img/cursor.png b/TP/TP01/P02/img/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..5b4a20e63078ce18bb11a4e601a1994b261522ef Binary files /dev/null and b/TP/TP01/P02/img/cursor.png differ diff --git a/TP/TP01/P02/img/d1db9286-d696-3dc3-2016-ac6bac7caa42.png b/TP/TP01/P02/img/d1db9286-d696-3dc3-2016-ac6bac7caa42.png new file mode 100644 index 0000000000000000000000000000000000000000..d75d0e360b3c9581788ee9b23b3d40913c0020d9 Binary files /dev/null and b/TP/TP01/P02/img/d1db9286-d696-3dc3-2016-ac6bac7caa42.png differ diff --git a/TP/TP01/P02/img/e1f3f8d9-b4c2-e9b1-78be-b5384c0608a5.png b/TP/TP01/P02/img/e1f3f8d9-b4c2-e9b1-78be-b5384c0608a5.png new file mode 100644 index 0000000000000000000000000000000000000000..752dfb28cbd1c1d7d47ac5822b2d53ca80d8baf2 Binary files /dev/null and b/TP/TP01/P02/img/e1f3f8d9-b4c2-e9b1-78be-b5384c0608a5.png differ diff --git a/TP/TP01/P02/img/f6edf30b-b3c9-992b-5a29-2899155fc088.png b/TP/TP01/P02/img/f6edf30b-b3c9-992b-5a29-2899155fc088.png new file mode 100644 index 0000000000000000000000000000000000000000..0eee77f040bb93a93846dd9166ce9612dc4aa6ab Binary files /dev/null and b/TP/TP01/P02/img/f6edf30b-b3c9-992b-5a29-2899155fc088.png differ diff --git a/TP/TP01/P02/img/fa328a63-2ce8-9ff6-de8b-cadc7cca7571.png b/TP/TP01/P02/img/fa328a63-2ce8-9ff6-de8b-cadc7cca7571.png new file mode 100644 index 0000000000000000000000000000000000000000..939d65d68ec9ea111f3d2d22a11945e615aebc83 Binary files /dev/null and b/TP/TP01/P02/img/fa328a63-2ce8-9ff6-de8b-cadc7cca7571.png differ diff --git a/TP/TP01/P02/img/fd27154d-26f4-d228-a651-ea2d3867a896.png b/TP/TP01/P02/img/fd27154d-26f4-d228-a651-ea2d3867a896.png new file mode 100644 index 0000000000000000000000000000000000000000..addb4ebd8aba8c9fa6c9fae1bbb8ceb9e18bf315 Binary files /dev/null and b/TP/TP01/P02/img/fd27154d-26f4-d228-a651-ea2d3867a896.png differ diff --git a/TP/TP01/P02/index.html b/TP/TP01/P02/index.html new file mode 100644 index 0000000000000000000000000000000000000000..ccff12ed96c3dc04d37577ee86195e6e0af8d602 --- /dev/null +++ b/TP/TP01/P02/index.html @@ -0,0 +1,420 @@ +<!DOCTYPE html> + +<html lang="en"> + +<head> +<title>Dahu Presentation +</title> +<meta charset="utf-8"> +<script src="http://code.jquery.com/jquery-1.9.1.min.js" type="text/javascript"> +</script> +<script src="parse-search.js" type="text/javascript"> +</script> + +<link rel="stylesheet" href="dahuapp.viewer.css"><style>.s0-o2{background-color: #FFFFDD;width: 240px} +.s2-o2{background-color: #FFFFDD;width: 240px} +.s4-o2{background-color: #FFFFDD;width: 240px} +.s6-o2{background-color: #FFFFDD;width: 240px} +.s7-o2{background-color: #FFFFDD;width: 240px} +.s8-o2{background-color: #FFFFDD;width: 240px} +.s9-o2{background-color: #FFFFDD;width: 240px} +.s10-o2{background-color: #FFFFDD;width: 240px} +.s11-o2{background-color: #FFFFDD;width: 240px} +.s12-o2{background-color: #FFFFDD;width: 240px} +</style> +</head> + +<body> + +<div id="my-dahu-presentation"> + +<div id="loading">Loading presentation... +</div> + +<div class="object-list" style="display: none"> +<img src="img/47b1d9d8-377e-8956-12e0-1a5855936ad9.png" alt="img/47b1d9d8-377e-8956-12e0-1a5855936ad9.png" class="background 47b1d9d8-377e-8956-12e0-1a5855936ad90"> + +<div class="tooltip s0-o2">Ouvrir l'écran du bloc Oscilloscope par un double-clic sur le bloc. +</div> +<img src="img/88d9520b-2d83-1911-c07c-adc370f752ad.png" alt="img/88d9520b-2d83-1911-c07c-adc370f752ad.png" class="background 88d9520b-2d83-1911-c07c-adc370f752ad0"> +<img src="img/5cc446dc-d0c1-0797-7b20-7b193c939258.png" alt="img/5cc446dc-d0c1-0797-7b20-7b193c939258.png" class="background 5cc446dc-d0c1-0797-7b20-7b193c9392580"> + +<div class="tooltip s2-o2">Ouvrir la configuration de la simulation. +</div> +<img src="img/1895ad3f-8322-65f5-cc85-a730ee6a9102.png" alt="img/1895ad3f-8322-65f5-cc85-a730ee6a9102.png" class="background 1895ad3f-8322-65f5-cc85-a730ee6a91020"> +<img src="img/f6edf30b-b3c9-992b-5a29-2899155fc088.png" alt="img/f6edf30b-b3c9-992b-5a29-2899155fc088.png" class="background f6edf30b-b3c9-992b-5a29-2899155fc0880"> + +<div class="tooltip s4-o2">Démarrer la simulation. +</div> +<img src="img/3f6a7fc7-c0ae-d0e6-416c-9164a0311aa4.png" alt="img/3f6a7fc7-c0ae-d0e6-416c-9164a0311aa4.png" class="background 3f6a7fc7-c0ae-d0e6-416c-9164a0311aa40"> +<img src="img/a8a2a39c-ff74-dc5b-d479-61864f684c7a.png" alt="img/a8a2a39c-ff74-dc5b-d479-61864f684c7a.png" class="background a8a2a39c-ff74-dc5b-d479-61864f684c7a0"> + +<div class="tooltip s6-o2">Mettre à l'échelle l'écran de l'oscilloscope. +</div> +<img src="img/551c31b6-7df8-0500-8bc8-55e8283c8ca9.png" alt="img/551c31b6-7df8-0500-8bc8-55e8283c8ca9.png" class="background 551c31b6-7df8-0500-8bc8-55e8283c8ca90"> + +<div class="tooltip s7-o2">Passer en mode de simulation à pas fixe (Fixed step). +</div> +<img src="img/99e6c70e-5d6f-796d-d931-04aef1b87fe2.png" alt="img/99e6c70e-5d6f-796d-d931-04aef1b87fe2.png" class="background 99e6c70e-5d6f-796d-d931-04aef1b87fe20"> + +<div class="tooltip s8-o2">Démarrer la simulation. +</div> +<img src="img/e1f3f8d9-b4c2-e9b1-78be-b5384c0608a5.png" alt="img/e1f3f8d9-b4c2-e9b1-78be-b5384c0608a5.png" class="background e1f3f8d9-b4c2-e9b1-78be-b5384c0608a50"> + +<div class="tooltip s9-o2">Mettre à l'échelle l'écran de l'oscilloscope. Vous ne constatez pas de différence avec la simulation à pas variable. +</div> +<img src="img/4cd13680-2e47-849f-6779-e9f8967d51b8.png" alt="img/4cd13680-2e47-849f-6779-e9f8967d51b8.png" class="background 4cd13680-2e47-849f-6779-e9f8967d51b80"> + +<div class="tooltip s10-o2">Changer le pas de simulation. Passer à 1 s. +</div> +<img src="img/9f513610-b961-16aa-61b5-06227f763eb4.png" alt="img/9f513610-b961-16aa-61b5-06227f763eb4.png" class="background 9f513610-b961-16aa-61b5-06227f763eb40"> + +<div class="tooltip s11-o2">Démarrer la simulation. +</div> +<img src="img/16f02396-3c95-ab6a-c7af-c6e6aa4c708a.png" alt="img/16f02396-3c95-ab6a-c7af-c6e6aa4c708a.png" class="background 16f02396-3c95-ab6a-c7af-c6e6aa4c708a0"> + +<div class="tooltip s12-o2">Mettre à l'échelle l'écran de l'oscilloscope. Constater que la sinusoïde affichée est maintenant linéaire par morceau. +</div> + +<div class="mouse-cursor"> +<img src="img/cursor.png" alt="img/cursor.png" class="mouse-cursor-normal"> +<img src="img/cursor-pause.png" alt="img/cursor-pause.png" style="display: none" class="mouse-cursor-pause"> +</div> +</div> + +<div class="control" style="top: 616px;"> +<button class="previous">Previous +</button> +<button class="next">Next +</button> +</div> +</div> +<script src="dahuapp.js" type="text/javascript"> +</script> +<script src="dahuapp.viewer.js" type="text/javascript"> +</script> +<script type="text/javascript">(function($) { + var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams); + myPresentation.load({ + "metaData": { + "imageWidth": 800, + "imageHeight": 600, + "initialBackgroundId": "47b1d9d8-377e-8956-12e0-1a5855936ad90", + "initialMouseX": 0.3173611111111111, + "initialMouseY": 0.25555555555555554 + }, + "action": [ + { + "id": "49", + "type": "appear", + "target": "s0-o2", + "trigger": "afterPrevious", + "abs": 0.21666666666666667, + "ord": 0.14125, + "duration": 400 + }, + { + "id": "3", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3173611111111111, + "finalOrd": 0.2577777777777778, + "speed": 0.8 + }, + { + "id": "4", + "type": "appear", + "target": "88d9520b-2d83-1911-c07c-adc370f752ad0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "5", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.20694444444444443, + "finalOrd": 0.10555555555555556, + "speed": 0.8 + }, + { + "id": "6", + "type": "appear", + "target": "5cc446dc-d0c1-0797-7b20-7b193c9392580", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "50", + "type": "appear", + "target": "s2-o2", + "trigger": "afterPrevious", + "abs": 0.17833333333333334, + "ord": 0.07875, + "duration": 400 + }, + { + "id": "7", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.20694444444444443, + "finalOrd": 0.10666666666666667, + "speed": 0.8 + }, + { + "id": "8", + "type": "appear", + "target": "1895ad3f-8322-65f5-cc85-a730ee6a91020", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "9", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.28958333333333336, + "finalOrd": 0.10555555555555556, + "speed": 0.8 + }, + { + "id": "10", + "type": "appear", + "target": "f6edf30b-b3c9-992b-5a29-2899155fc0880", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "51", + "type": "appear", + "target": "s4-o2", + "trigger": "afterPrevious", + "abs": 0.22833333333333333, + "ord": 0.085, + "duration": 400 + }, + { + "id": "13", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2916666666666667, + "finalOrd": 0.1, + "speed": 0.8 + }, + { + "id": "14", + "type": "appear", + "target": "3f6a7fc7-c0ae-d0e6-416c-9164a0311aa40", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "15", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.14583333333333334, + "finalOrd": 0.6633333333333333, + "speed": 0.8 + }, + { + "id": "16", + "type": "appear", + "target": "a8a2a39c-ff74-dc5b-d479-61864f684c7a0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "52", + "type": "appear", + "target": "s6-o2", + "trigger": "afterPrevious", + "abs": 0.09833333333333333, + "ord": 0.2975, + "duration": 400 + }, + { + "id": "17", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.5638888888888889, + "finalOrd": 0.7466666666666667, + "speed": 0.8 + }, + { + "id": "18", + "type": "appear", + "target": "551c31b6-7df8-0500-8bc8-55e8283c8ca90", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "53", + "type": "appear", + "target": "s7-o2", + "trigger": "afterPrevious", + "abs": 0.39666666666666667, + "ord": 0.32875, + "duration": 400 + }, + { + "id": "19", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2923611111111111, + "finalOrd": 0.09666666666666666, + "speed": 0.8 + }, + { + "id": "20", + "type": "appear", + "target": "99e6c70e-5d6f-796d-d931-04aef1b87fe20", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "54", + "type": "appear", + "target": "s8-o2", + "trigger": "afterPrevious", + "abs": 0.17833333333333334, + "ord": 0.0775, + "duration": 400 + }, + { + "id": "27", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.14375, + "finalOrd": 0.6666666666666666, + "speed": 0.8 + }, + { + "id": "28", + "type": "appear", + "target": "e1f3f8d9-b4c2-e9b1-78be-b5384c0608a50", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "55", + "type": "appear", + "target": "s9-o2", + "trigger": "afterPrevious", + "abs": 0.075, + "ord": 0.3025, + "duration": 400 + }, + { + "id": "29", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.7118055555555556, + "finalOrd": 0.7722222222222223, + "speed": 0.8 + }, + { + "id": "30", + "type": "appear", + "target": "4cd13680-2e47-849f-6779-e9f8967d51b80", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "56", + "type": "appear", + "target": "s10-o2", + "trigger": "afterPrevious", + "abs": 0.24166666666666667, + "ord": 0.33375, + "duration": 400 + }, + { + "id": "39", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.28680555555555554, + "finalOrd": 0.1, + "speed": 0.8 + }, + { + "id": "40", + "type": "appear", + "target": "9f513610-b961-16aa-61b5-06227f763eb40", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "57", + "type": "appear", + "target": "s11-o2", + "trigger": "afterPrevious", + "abs": 0.2, + "ord": 0.08625, + "duration": 400 + }, + { + "id": "31", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.1451388888888889, + "finalOrd": 0.6666666666666666, + "speed": 0.8 + }, + { + "id": "32", + "type": "appear", + "target": "16f02396-3c95-ab6a-c7af-c6e6aa4c708a0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "58", + "type": "appear", + "target": "s12-o2", + "trigger": "afterPrevious", + "abs": 0.22166666666666668, + "ord": 0.28125, + "duration": 400 + } + ] +}); + myPresentation.start(); +})(jQuery); + +</script> +</body> +</html> \ No newline at end of file diff --git a/TP/TP01/P02/parse-search.js b/TP/TP01/P02/parse-search.js new file mode 100644 index 0000000000000000000000000000000000000000..e7d01c07f6a5d45b9fcabd5d271a8c6cfc5f00e2 --- /dev/null +++ b/TP/TP01/P02/parse-search.js @@ -0,0 +1,14 @@ +// Adapted from http://stackoverflow.com/questions/3234125/creating-array-from-window-location-hash +(function () { + var search = window.location.search.slice(1); + var array = search.split("&"); + + var values, form_data = {}; + + for (var i = 0; i < array.length; i += 1) { + values = array[i].split("="); + form_data[values[0]] = unescape(values[1]); + } + window.getParams = form_data; +}()) + diff --git a/TP/TP01/P03/dahuapp.js b/TP/TP01/P03/dahuapp.js new file mode 100644 index 0000000000000000000000000000000000000000..41c69e9169345a9a6703325d5557a4cc36913e19 --- /dev/null +++ b/TP/TP01/P03/dahuapp.js @@ -0,0 +1,880 @@ +"use strict"; + +/** + * Dahuapp core module. + * + * @param window window javascript object. + * @param $ jQuery + * @returns dahuapp core module. + */ +(function (window, $) { + var dahuapp = (function () { + + var self = {}; + + /* private API */ + + var DahuScreencastGenerator = function () { + + /* + * Format the specified string in a readable format. + */ + function htmlFormat(htmlString) { + var i; + var readableHTML = htmlString; + var lb = '\n'; + var htags = ["<html", "</html>", "</head>", "<title", "</title>", "<meta", "<link", "</body>"]; + for (i = 0; i < htags.length; ++i) { + var hhh = htags[i]; + readableHTML = readableHTML.replace(new RegExp(hhh, 'gi'), lb + hhh); + } + var btags = ["</div>", "</section>", "</span>", "<br>", "<br />", "<blockquote", "</blockquote>", "<ul", "</ul>", "<ol", "</ol>", "<li", "<\!--", "<script", "</script>"]; + for (i = 0; i < btags.length; ++i) { + var bbb = btags[i]; + readableHTML = readableHTML.replace(new RegExp(bbb, 'gi'), lb + bbb); + } + var ftags = ["<img", "<legend", "</legend>", "<button", "</button>"]; + for (i = 0; i < ftags.length; ++i) { + var fff = ftags[i]; + readableHTML = readableHTML.replace(new RegExp(fff, 'gi'), lb + fff); + } + var xtags = ["<body", "<head", "<div", "<section", "<span", "<p"]; + for (i = 0; i < xtags.length; ++i) { + var xxx = xtags[i]; + readableHTML = readableHTML.replace(new RegExp(xxx, 'gi'), lb + lb + xxx); + } + return readableHTML; + } + + /* + * Generates the html header. + */ + var generateHtmlHeader = function ($generated, cssGen) { + $('head', $generated) + .append($(document.createElement('title')) + .append("Dahu Presentation"))/* TODO: make this customizable */ + .append($(document.createElement('meta')) + .attr({'charset': 'utf-8'})) + .append($(document.createElement('script')) + .attr({'src': 'http://code.jquery.com/jquery-1.9.1.min.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'parse-search.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('link')) + .attr({'rel': 'stylesheet', 'href': 'dahuapp.viewer.css'})) + .append($(document.createElement('style')) + .append(cssGen)); + }; + + /* + * Generates the objects. + */ + + var generateHtmlBackgroundImage = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('img')) + .attr({'src': object.img, 'alt': object.img, 'class': 'background ' + object.id})); + }; + var generateHtmlTooltip = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'tooltip ' + object.id}) + .append(object.text)); + }; + + var generateCssTooltip = function ($generated, object) { + var style = []; + + if( object.color != null ) { + style.push('background-color: ' + object.color); + } + if( object.width != null ) { + style.push('width: ' + object.width); + } + + if( style.length != 0 ) { + $generated.append( + '.' + object.id + '{' + style.join(';') + '}\n'); + } + + return $generated; + }; + + /* + * Returns the code used to call the viewer to the presentation. + */ + var getBasicCallCode = function (jsonModel) { + var code = '(function($) {\n'; + code += ' var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams);\n'; + code += ' myPresentation.load(' + jsonModel + ');\n'; + code += ' myPresentation.start();\n'; + code += '})(jQuery);\n'; + return code; + }; + + /* + * Generates the html body. + */ + var generateHtmlBody = function ($generated, jsonModel, jsonGen) { + $('body', $generated) + /* We could use a <section> here too, but it does not work with MS IE 8. + Alternatively, adding this in the header would work: + + <!--[if lt IE 9]> + <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + */ + .append($(document.createElement('div')) + .attr({'id': 'my-dahu-presentation'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.viewer.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'type': 'text/javascript'}) + .append(getBasicCallCode(jsonGen))); + $('#my-dahu-presentation', $generated) + .append($(document.createElement('div')) + .attr({'id': 'loading'}).append("Loading presentation...")) + .append($(document.createElement('div')) + .attr({'class': 'object-list', + 'style': 'display: none'})) + .append($(document.createElement('div')) + .attr({'class': 'control'})); + + /* Adding the objects to the page */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "background": + generateHtmlBackgroundImage($generated, object); + break; + case "tooltip": + generateHtmlTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + /* Warning here, i'm not sure if $.each is always over, here */ + + /* Adding the control buttons to the page */ + $('.control', $generated) + .css({'top': (jsonModel.getImageHeight() + 16) + 'px'}) + .append($(document.createElement('button')) + .attr({'class': 'previous'}) + .append('Previous')) + .append($(document.createElement('button')) + .attr({'class': 'next'}) + .append('Next')); + + /* Adding the mouse cursor image */ + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'mouse-cursor'}) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor.png', 'alt': 'img/cursor.png', 'class': 'mouse-cursor-normal'})) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor-pause.png', 'alt': 'img/cursor-pause.png', + 'style': 'display: none', 'class': 'mouse-cursor-pause'}))); + }; + + /* + * Generates the css String with the Json model. + */ + this.generateCssString = function (jsonModel) { + var $generated = $('<style></style>'); + + /* Going through each object */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "tooltip": + generateCssTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + return $generated.text(); + } + + /* + * Generates the html String with the Json model. + */ + this.generateHtmlString = function (jsonModel, jsonGen, cssGen) { + /* Initialising the compilation area */ + var $generated = $(document.createElement('div')); + + /* We create the html using the json */ + $generated.append($(document.createElement('html')) + .attr({'lang': 'en'})); + $('html', $generated) + .append($(document.createElement('head'))) + .append($(document.createElement('body'))); + + generateHtmlHeader($generated, cssGen); + generateHtmlBody($generated, jsonModel, jsonGen); + + var result = htmlFormat($generated.html()); + + return '<!DOCTYPE html>\n' + result; + }; + + /* + * Generates the generated JSON using the JSONmodel. + * @param {object} jsonModel The json model to transform. + * @param {java.awt.Dimension} imgDim The dimension of images. + */ + this.generateJsonString = function (jsonModel, imgDim) { + var generated = self.createScreencastGeneratedModel(); + generated.setImageSize(imgDim.width, imgDim.height); + generated.setInitialBackground(jsonModel.getInitialBackground()); + generated.setInitialMousePos(jsonModel.getInitialMousePos()); + for (var i = 0; i < jsonModel.getNbSlide(); i++) { + var actionList = jsonModel.getActionList(i); + for (var j = 0; j < actionList.length; j++) { + /* + * We don't add the two first actions of the first slide + * because they are present in the presentation metadata. + * It corresponds to the mouse initial pos and first background. + */ + if (i > 0 || j > 1) { + generated.addAction(actionList[j], imgDim.width, imgDim.height); + } + } + } + return generated.getJson(); + }; + }; + + /* + * Model for a JSON object that will only be used by the viewer, never + * saved on a file, used to transform the properties of actions + * specified on the JSON file of a presentation to executable + * functions for each action. + */ + var DahuScreencastExecutableModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* + * Creates a functions representing the specified action, and adds + * it to this object. + * @param {object} action + */ + var addExecutableAction = function (action) { + var executableAction = { + 'id': action.id, + 'trigger': action.trigger, + 'target': action.target, + 'delayAfter': action.delayAfter, + 'doneFunction': function (events, selector) { + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.delayAfter); + } + }; + if (executableAction.delayAfter == null) { + executableAction.delayAfter = 200; + } + switch (action.type.toLowerCase()) { + case "appear": + executableAction.abs = (action.abs * json.metaData.imageWidth) + 'px'; + executableAction.ord = (action.ord * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(); + }; + break; + case "disappear": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + $(selector + ' .' + this.target).hide(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).show(); + }; + executableAction.executeImmediately = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + break; + case "move": + executableAction.finalAbs = (action.finalAbs * json.metaData.imageWidth) + 'px'; + executableAction.finalOrd = (action.finalOrd * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.speed = action.speed; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + if (this.duration == null) { + var initialAbsPix = this.initialAbs.replace('px', ''); + var initialOrdPix = this.initialOrd.replace('px', ''); + var finalAbsPix = this.finalAbs.replace('px', ''); + var finalOrdPix = this.finalOrd.replace('px', ''); + var distance = Math.sqrt(Math.pow(finalAbsPix - initialAbsPix, 2) + + Math.pow(finalOrdPix - initialOrdPix, 2)); + if (!this.speed) { + this.speed = .8; // in pixel per milisecond: fast, but not too much. + } + this.duration = distance + this.speed; + if (this.duration < 200) { // Slow down a bit for short distances. + this.duration = 200; + } + } + $(sel).animate({ + 'left': this.finalAbs, + 'top': this.finalOrd + }, this.duration, 'linear', function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).css({ + 'left': this.initialAbs, + 'top': this.initialOrd + }); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + $(sel).css({ + 'left': this.finalAbs, + 'top': this.finalOrd + }); + }; + break; + case "delay": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.duration); + }; + executableAction.executeReverse = function (selector) { + // Nothing! + }; + executableAction.executeImmediately = function (selector) { + // Nothing too! + }; + break; + } + json.action.push(executableAction); + }; + + /* Public API */ + + /* + * Loads the specified JSON read from a 'presentation.json' file, + * and stores the functions representing each actions in an object. + * @param {object} jsonToLoad + */ + this.loadJson = function (jsonToLoad) { + json.metaData = jsonToLoad.metaData; + for (var i = 0; i < jsonToLoad.action.length; i++) { + addExecutableAction(jsonToLoad.action[i]); + } + }; + + /* + * Returns the object containing the functions. + */ + this.getJson = function () { + return json; + }; + }; + + /* + * Used to transform the 'dahu' file to a JSON file used by the viewer, + * which only contains some metaData and a list of actions. + */ + var DahuScreencastGeneratedModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* Public API */ + + /* + * Returns a string representation of this json. + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * Setters for the generated json metadata. + */ + this.setImageSize = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + this.setInitialMousePos = function (pos) { + json.metaData.initialMouseX = pos.x; + json.metaData.initialMouseY = pos.y; + }; + + this.setInitialBackground = function (id) { + json.metaData.initialBackgroundId = id; + }; + + this.addAction = function (action) { + json.action.push(action); + }; + + /* + * Transforms a JSON containing action properties to a JSON containing + * the execution functions. + * @param {Object} json + * @returns {Object} A json object containing the execution functions + * for all the actions of the presentation. + */ + this.toExecutableList = function (json) { + var executableList = { + metaData: json.metaData, + action: new Array() + }; + for (var i = 0; i < json.action.length; i++) { + addExecutableAction(executableList, json.action[i]); + } + return executableList; + }; + }; + + /* + * Represents a 'dahu' file for a project. + */ + var DahuScreencastModel = function () { + + /* Private API */ + + var json = {}; + + /* + * Generates a unique action ID. + * + * With this implementation, this ID is unique as long as the user + * doesn't replace it manually with a not kind value or replace + * the nextUniqueId with bad intentions. + * But maybe that a UUID is a bit tiresome to put as an anchor... + */ + var generateUniqueActionId = function () { + json.metaData.nextUniqueId++; + return json.metaData.nextUniqueId.toString(); + }; + + /* + * This method checks if the json representing a dahu project is + * in the good version. It's in case a project file was created + * with a previous version of Dahu, and that some fields are + * missing. + * + * It doesn't control each field (at the moment) but only the + * fields that can be missing due to a new Dahu version and not + * to a manual editing. + * + * This method doesn't check any Json syntax or something like that. + */ + var upgradeJsonVersion = function () { + // Checks if unique IDs are in the project file + if (!json.metaData.nextUniqueId) { + var currentId = 0; + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].action.length; j++) { + json.data[i].action[j].id = currentId.toString(); + currentId++; + } + } + json.metaData.nextUniqueId = currentId; + } + }; + + /* Public API */ + + /* + * json variable generated from a JSON file. + * @param String stringJson String loaded from JSON file. + */ + this.loadJson = function (stringJson) { + json = JSON.parse(stringJson); + upgradeJsonVersion(); + }; + + /* + * Create a new presentation variable in the JSON file which will contain slides. + */ + this.createPresentation = function (width, height) { + json.metaData = {}; + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + json.metaData.nextUniqueId = 0; + json.data = new Array(); + }; + + /* + * Add a new slide in the presentation variable of the JSON file. + * @param int index wanted for the slide. + * @param String idSlide Unique identifier for the slide. + * @param String img Related to pathname of the image. + * @param double mouseX Abscissa mouse position in %. + * @param double mouseY Ordinate mouse position in %. + * @return Index of the newly added slide. + */ + this.addSlide = function (indexSlide, idSlide, img, mouseX, mouseY, speed) { + var slide = { + "object": new Array(), + "action": new Array() + }; + json.data.splice(indexSlide, 0, slide); + this.addObject(indexSlide, "background", idSlide, img); + this.addObject(indexSlide, "mouse"); + this.addAction(indexSlide, "move", json.data[indexSlide].object[1].id, "onClick", mouseX, mouseY, speed); + this.addAction(indexSlide, "appear", json.data[indexSlide].object[0].id, "afterPrevious"); + }; + + /* + * Object factory. + * Add a new Object in the slide idSlide. + * @param int idSlide + * @param string type + * Other params can be specified depending on the object's type. + */ + this.addObject = function (idSlide, type) { + var object = { + "type": type + }; + switch (type.toLowerCase()) { + case "background": + object.id = arguments[2] + json.data[idSlide].object.length; + object.img = arguments[3] || ""; + break; + case "mouse": + object.id = "mouse-cursor"; + break; + case "tooltip": + /* + * TODO: we'll need a more robust unique name + * when we start actually using this. + */ + object.id = "s" + idSlide + "-o" + json.data[idSlide].object.length; + object.text = arguments[2] || ""; + object.color = arguments[3] || null; + object.width = arguments[4] || ""; + json.data[idSlide].object.push(object); + var objectLength = json.data[idSlide].object.length; + var last = json.data[idSlide].object[objectLength-1]; + json.data[idSlide].object[objectLength-1] = + json.data[idSlide].object[objectLength-2]; + json.data[idSlide].object[objectLength-2] = last; + break; + } + if(type.toLowerCase() != "tooltip"){ + json.data[idSlide].object.push(object); + } + }; + + /* + * Action factory. + * Add a new Action in the slide idSlide whose target is the id of an object. + * Three types of trigger : "withPrevious", "afterPrevious", "onClick". + * @param int idSlide + * @param string type + * @param string target + * @param string trigger + * Other params can be specified depending on the object's type. + */ + this.addAction = function (idSlide, type, target, trigger) { + var action = { + "id": generateUniqueActionId(), + "type": type, + "target": target, + "trigger": trigger + }; + switch (type.toLowerCase()) { + case "appear": + action.abs = arguments[4] || 0.0; + action.ord = arguments[5] || 0.0; + action.duration = arguments[6] || 0; + break; + case "disappear": + action.duration = arguments[4] || 0; + break; + case "move": + action.finalAbs = arguments[4] || 0.0; + action.finalOrd = arguments[5] || 0.0; + action.speed = arguments[6] || 0; + break; + } + json.data[idSlide].action.push(action); + }; + + this.editMouse = function (idSlide, idAction, mouseX, mouseY) { + json.data[idSlide].action[idAction].finalAbs = mouseX; + json.data[idSlide].action[idAction].finalOrd = mouseY; + }; + + /* + * Sets a title for the presentation. + * @param String title Title to set. + */ + this.setTitle = function (title) { + json.metaData.title = title; + }; + + /* + * Sets an annotation for the presentation. + * @param String annotation Annotation to set. + */ + this.setAnnotation = function (annotation) { + json.metaData.annotation = annotation; + }; + + /* + * Inverts the two slides (their positions on the table). + * @param int idSlide1 Index of the first slide. + * @param int idSlide2 Index of the second slide. + */ + this.invertSlides = function (idSlide1, idSlide2) { + var tmp = json.data[idSlide1]; + json.data[idSlide1] = json.data[idSlide2]; + json.data[idSlide2] = tmp; + }; + + /* + * Inverts the two actions (their positions on the table). + * @param int idSlide + * @param int idAction1 + * @param int idAction2 + */ + this.invertActions = function (idSlide, idAction1, idAction2) { + var tmp = json.data[idSlide].action[idAction1]; + json.data[idSlide].action[idAction1] = json.data[idSlide].action[idAction2]; + json.data[idSlide].action[idAction2] = tmp; + }; + + /* + * Returns the actions on the specified slide. + * @returns {Array} + */ + this.getActionList = function (idSlide) { + return json.data[idSlide].action; + }; + + /* + * Catches all the objects of the presentation + * @returns {Array} List of objects of the presentation + */ + this.getObjectList = function () { + var objectList = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + var indexObject = 0; + while (json.data[indexSlide].object[indexObject]) { + objectList.push(json.data[indexSlide].object[indexObject]); + indexObject++; + } + indexSlide++; + } + return objectList; + }; + + /* + * Returns an array containing all the background images. + * @returns {Array} List of background images. + */ + this.getImageList = function () { + var list = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + list.push(json.data[indexSlide].object[0].img); + indexSlide++; + } + ; + return list; + }; + + /* + * Returns an object containing the id of the first background. + * @returns {string} Id of the first background. + */ + this.getInitialBackground = function () { + return json.data[0].object[0].id; + }; + + /* + * Returns an object containing the initial mouse position. + * @returns {object} Initial position of mouse. + */ + this.getInitialMousePos = function () { + var pos = {}; + pos.x = json.data[0].action[0].finalAbs; + pos.y = json.data[0].action[0].finalOrd; + return pos; + }; + + /* + * Removes the slide at the specified index. + * @param {int} idSlide + */ + this.removeSlide = function (idSlide) { + json.data.splice(idSlide, 1); + }; + + /* + * Removes the action at the specified slide. + * @param {int} idSlide + * @param {int} idAction + */ + this.removeAction = function (idSlide, idAction) { + json.data[idSlide].action.splice(idAction, 1); + }; + + /* + * Removes the specified object from the slide. + * Also removes all the actions attached to this object. + * @param {int} idSlide + * @param {int} idObject + */ + this.removeObject = function (idSlide, idObject) { + var removed = json.data[idSlide].object.splice(idObject, 1); + for (var i = 0; i < json.data.length; i++) { + var j = 0; + while (json.data[i].action[j]) { + if (json.data[i].action[j].target === removed.id) { + json.data[i].action.splice(j, 1); + } else { + j++; + } + } + } + }; + + /* + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * @returns {String} returns the index for the next slide. + */ + this.getNbSlide = function () { + return json.data.length; + }; + + /* + * @return {object} returns the object identified by idSlide + */ + this.getSlide = function (idSlide) { + return json.data[idSlide]; + }; + + /* + * Sets the size of images for the generated presentation. + * The parameters can be null : it means there are no + * requirement for this dimension. + * @param {int} width New width for the generated images. + * @param {int} height New height for the generated images. + */ + this.setImageSizeRequirements = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + /* + * Gets the width of images for the generated presentation. + * @return {int or null} Width of generated images. + */ + this.getImageWidth = function () { + return json.metaData.imageWidth; + }; + + /* + * Gets the height of images for the generated presentation. + * @return {int or null} Height of generated images. + */ + this.getImageHeight = function () { + return json.metaData.imageHeight; + }; + + /* + * Gets a background image (no one in particular, the first met). + * @return {string} The name of a background image. + */ + this.getABackgroundImage = function () { + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].object.length; j++) { + if (json.data[i].object[j].type === "background") { + return json.data[i].object[j].img; + } + } + } + return null; + }; + }; + + /* public API */ + + self.version = "0.0.1"; + + self.createScreencastGenerator = function createScreencastGenerator() { + return new DahuScreencastGenerator(); + }; + + self.createScreencastModel = function createScreencastModel() { + return new DahuScreencastModel(); + }; + + self.createScreencastExecutableModel = function createScreencastExecutableModel() { + return new DahuScreencastExecutableModel(); + }; + + self.createScreencastGeneratedModel = function createScreencastGeneratedModel() { + return new DahuScreencastGeneratedModel(); + }; + + return self; + })(); + + window.dahuapp = dahuapp; + +})(window, jQuery); \ No newline at end of file diff --git a/TP/TP01/P03/dahuapp.viewer.css b/TP/TP01/P03/dahuapp.viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ea934576dad6ca9263a6163de58f5fe4534d1f0b --- /dev/null +++ b/TP/TP01/P03/dahuapp.viewer.css @@ -0,0 +1,25 @@ +.object-list { + position: absolute; + margin: 0px; + padding: 0px; +} + +.mouse-cursor { + position: absolute; +} + +.control { + position: relative; +} + +.background { + position: absolute; +} + +.tooltip { + position: absolute; + width: 100px; + padding: 4px; + margin: 2px; + border: 2px black solid; +} \ No newline at end of file diff --git a/TP/TP01/P03/dahuapp.viewer.js b/TP/TP01/P03/dahuapp.viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..12ad03b2cdc503a8fd6ff3f5fdc2a74edbb36edb --- /dev/null +++ b/TP/TP01/P03/dahuapp.viewer.js @@ -0,0 +1,456 @@ +"use strict"; + +/** + * Dahuapp viewer module. + * + * @param dahuapp dahuapp object to augment with module. + * @param $ jQuery + * @returns dahuapp extended with viewer module. + */ + +(function(dahuapp, $) { + var viewer = (function() { + + var self = {}; + + var DahuViewerModel = function(select, getParams) { + + /* Private API */ + + var json = null; + var selector = select; + var parseAutoOption = function(name, defaultValue) { + var res = getParams[name]; + if (res == null) { + if (name == 'auto') { + return false; + } else { + return parseAutoOption('auto', defaultValue); + } + } + if (res.toLowerCase() === 'false') { + return false; + } + res = parseInt(res); + if (isNaN(res)) { + // e.g. ?autoplay or ?autoplay=true + return defaultValue; + } + return res; + } + + /* Whether to wait for "next" event between actions */ + var autoPlay = parseAutoOption('autoplay', 5000); + /* Whether to wait for "next" event on page load */ + var autoStart = parseAutoOption('autostart', 5000); + /* Whether to loop back to start at the end of presentation */ + var autoLoop = parseAutoOption('autoloop', 5000); + + var events = (function() { + var self = {}; + /* + * Creates a generic event. + */ + var createEvent = function() { + var callbacks = $.Callbacks(); + return { + publish: callbacks.fire, + subscribe: callbacks.add, + unsubscribe: callbacks.remove, + unsubscribeAll: callbacks.empty + }; + }; + /* + * Called when the button next is pressed. + */ + self.onNext = createEvent(); + /* + * Called when the button previous is pressed. + */ + self.onPrevious = createEvent(); + /* + * Called when an action is over. + */ + self.onActionOver = createEvent(); + /* + * Called when an action starts. + */ + self.onActionStart = createEvent(); + /* + * Called when at least one action was running and has finished. + */ + self.onAllActionFinish = createEvent(); + + return self; + })(); + + /* + * Variables used like index for methodes subscribed. + */ + var currentAction = 0; /* Action currently running */ + var nextAction = 0; /* Action to execute on 'Next' click */ + var nbActionsRunning = 0; + var previousAnchor = -1; /* Last entered anchor, only used in + * case the 'onhashchange' event is + * not supported by the web browser */ + + /* + * Functions to reinitialise running actions and subscribed + * callbacks (reinitialise is called once without stopping + * all the actions, so the two functions are separated). + */ + var stopAllActions = function() { + $(selector + " .object-list").children().stop(true, true); + reinitialiseCallbackLists(); + nbActionsRunning = 0; + }; + var reinitialiseCallbackLists = function() { + events.onActionStart.unsubscribeAll(); + events.onActionStart.subscribe(onActionStartEventHandler); + events.onAllActionFinish.unsubscribeAll(); + }; + + /* + * Timer used to program onNext event in autoplay mode. + */ + var playTimer = 0; + + /* + * Function used when an "onNextEvent" event is caught. + */ + var onNextEventHandler = function() { + /* + * If the user pressed "next" before an autoplay event + * is triggered, it replaces the autoplay event, hence + * cancels it: + */ + window.clearTimeout(playTimer); + + enterAnimationMode(); + stopAllActions(); + var tmpAction = nextAction; + var onlyWithPrevious = true; + nextAction++; + currentAction = nextAction; + while (json.action[currentAction] && onlyWithPrevious) { + switch (json.action[currentAction].trigger) { + case 'onClick': + nextAction = currentAction; + onlyWithPrevious = false; + break; + case 'withPrevious': + var tmp = currentAction; + /* + * We can't directly pass 'execute' as callback because we + * allow the 'execute' function to reference a property of the + * object (by using 'this.property') so we have to call the + * function in the containing object to make that available + */ + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + while (json.action[nextAction] && json.action[nextAction].trigger !== 'onClick') { + nextAction++; + } + onlyWithPrevious = false; + break; + } + currentAction++; + } + if (json.action[tmpAction]) { + launch(json.action[tmpAction]); + } + if (nextAction > json.action.length) { + nextAction = json.action.length; + } + }; + + /* + * Function used when an "onPreviousEvent" event is caught. + */ + var onPreviousEventHandler = function() { + stopAllActions(); + currentAction = nextAction - 1; + while (json.action[currentAction] && json.action[currentAction].trigger !== 'onClick') { + launchReverse(json.action[currentAction]); + currentAction--; + } + /* currentAction = -1 means that it's the beginning */ + if (currentAction > -1) { + launchReverse(json.action[currentAction]); + } + if (currentAction < 0) { + currentAction = 0; + } + nextAction = currentAction; + }; + + /* + * Function used when an "onActionOverEvent" event is caught. + */ + var onActionOverEventHandler = function() { + nbActionsRunning--; + if (nbActionsRunning === 0) { + events.onAllActionFinish.publish(events, selector); + reinitialiseCallbackLists(); + while (json.action[currentAction]) { + switch (json.action[currentAction].trigger) { + case 'onClick': + leaveAnimationMode(); + if (autoPlay && nbActionsRunning === 0) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoPlay); + } + return; + case 'withPrevious': + var tmp = currentAction; + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + currentAction++; + return; + } + currentAction++; + + } + if (autoLoop && nbActionsRunning === 0) { + setTimeout(function () { + resetPresentation(); + startPresentationMaybe(); + }, autoLoop); + } + } + leaveAnimationMode(); + }; + + /* + * Function used when an "onActionStartEvent" event is caught. + */ + var onActionStartEventHandler = function() { + nbActionsRunning++; + }; + + /* + * Enter and leave "animation" mode. The viewer is in + * animation mode when something is going on without human + * interaction (i.e. executing actions before the next + * "onClick"). + */ + var enterAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').hide(); + $(selector + ' .mouse-cursor-normal').show(); + }; + + var leaveAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').show(); + $(selector + ' .mouse-cursor-normal').hide(); + }; + + /* + * Function used to perform actions. + */ + var launch = function(action) { + action.execute(events, selector); + }; + var launchReverse = function(action) { + action.executeReverse(selector); + }; + + /* + * The two following methods each returns an array containing the + * actions to execute to reach the given anchor (respectively + * forward or backwards). + * + * If the given anchor matches none of the actions, then an empty + * array is returned. + */ + var getActionsToJumpForward = function(anchor) { + var actions = new Array(); + for (var i = nextAction; i < json.action.length; i++) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + if (json.action[i].id == anchor) { + return actions; + } else { + actions.push(json.action[i]); + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + var getActionsToJumpBackwards = function(anchor) { + var actions = new Array(); + for (var i = nextAction - 1; i >= 0; i--) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + actions.push(json.action[i]); + if (json.action[i].id == anchor) { + return actions; + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + + /* + * Updates the position of the presentation depending on the + * given anchor (next action wanted). + */ + var jumpToAnchor = function(anchor) { + if (anchor !== '') { + stopAllActions(); + if (anchor > nextAction) { + // forward + var actions = getActionsToJumpForward(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeImmediately(selector); + } + nextAction += actions.length; + } else { + // backwards + var actions = getActionsToJumpBackwards(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeReverse(selector); + } + nextAction -= actions.length; + } + } + }; + + var resetPresentation = function() { + window.clearTimeout(playTimer); + + currentAction = 0; + nextAction = 0; + nbActionsRunning = 0; + + /* + * At the beginning, the visible image is the first one of the presentation + */ + $(selector + " .object-list").children().hide(); + + $(selector + " ." + json.metaData.initialBackgroundId).show(); + + $(selector + " .mouse-cursor").css({ + 'top': (json.metaData.initialMouseY * json.metaData.imageHeight) + "px", + 'left': (json.metaData.initialMouseX * json.metaData.imageWidth) + "px" + }); + + $(selector + " .mouse-cursor").show(); + } + + var startPresentationMaybe = function() { + if (autoStart) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoStart); + } + } + + /* Public API */ + + this.loadUrl = function(url) { + var dataJson; + $.ajax({ + 'async': false, + 'global': false, + 'url': url, + 'dataType': "json", + 'success': function(data) { + dataJson = data; + } + }); + + load(dataJson); + }; + + this.load = function(dataJson) { + /* Transforms data JSON to executable functions for actions */ + var execModel = dahuapp.createScreencastExecutableModel(); + execModel.loadJson(dataJson); + json = execModel.getJson(); + }; + + this.start = function() { + + /* + * Subscription of methods to their events. + */ + events.onNext.subscribe(onNextEventHandler); + events.onPrevious.subscribe(onPreviousEventHandler); + events.onActionOver.subscribe(onActionOverEventHandler); + events.onActionStart.subscribe(onActionStartEventHandler); + + resetPresentation(); + + /* + * If an anchor has been specified, we place the presentation + * in the right position. + */ + jumpToAnchor(window.location.hash.substring(1)); + + /* + * If the anchor changes during the presentation, then the + * presentation is updated + */ + if ("onhashchange" in window) { + // event supported + window.onhashchange = function () { + jumpToAnchor(window.location.hash.substring(1)); + }; + } else { + // event not supported : periodical check + window.setInterval(function () { + if (window.location.hash.substring(1) !== previousAnchor) { + previousAnchor = window.location.hash.substring(1); + jumpToAnchor(window.location.hash.substring(1)); + } + }, 100); + } + + /* + * A click on the "next" button publishes a nextSlide event + */ + $(selector + " .next").click(function() { + events.onNext.publish(); + }); + + /* + * A click on the "previous" button publishes a previousSlide event + */ + $(selector + " .previous").click(function() { + events.onPrevious.publish(); + }); + + /* + * Everything is ready, show the presentation + * (hidden with style="display: none" from HTML). + */ + $("#loading").hide(); + $(selector + " .object-list").show(); + startPresentationMaybe(); + }; + }; + + self.createDahuViewer = function(selector, getParams) { + return new DahuViewerModel(selector, getParams); + }; + + return self; + })(); + + dahuapp.viewer = viewer; +})(dahuapp || {}, jQuery); diff --git a/TP/TP01/P03/img/01f96120-1e41-b4d3-b844-e73128943106.png b/TP/TP01/P03/img/01f96120-1e41-b4d3-b844-e73128943106.png new file mode 100644 index 0000000000000000000000000000000000000000..5f9eef58766110297995e501937aed46ba98fe35 Binary files /dev/null and b/TP/TP01/P03/img/01f96120-1e41-b4d3-b844-e73128943106.png differ diff --git a/TP/TP01/P03/img/0edbde4a-26ff-f2d1-a88f-5a13affc536a.png b/TP/TP01/P03/img/0edbde4a-26ff-f2d1-a88f-5a13affc536a.png new file mode 100644 index 0000000000000000000000000000000000000000..36ad307589db8451026710a4dcd80a262bf28cee Binary files /dev/null and b/TP/TP01/P03/img/0edbde4a-26ff-f2d1-a88f-5a13affc536a.png differ diff --git a/TP/TP01/P03/img/1d9e476d-7d77-fc65-07f3-77174933ac05.png b/TP/TP01/P03/img/1d9e476d-7d77-fc65-07f3-77174933ac05.png new file mode 100644 index 0000000000000000000000000000000000000000..92449bd3cf3a46b6efd78899aa0ff65126793dd6 Binary files /dev/null and b/TP/TP01/P03/img/1d9e476d-7d77-fc65-07f3-77174933ac05.png differ diff --git a/TP/TP01/P03/img/30962ad0-d4f1-7ca3-4eaa-45b0066b27eb.png b/TP/TP01/P03/img/30962ad0-d4f1-7ca3-4eaa-45b0066b27eb.png new file mode 100644 index 0000000000000000000000000000000000000000..cba92a12052b130e626c1768aa4cbd2df781f617 Binary files /dev/null and b/TP/TP01/P03/img/30962ad0-d4f1-7ca3-4eaa-45b0066b27eb.png differ diff --git a/TP/TP01/P03/img/321ec853-941a-e69e-7fa1-eac7f318f366.png b/TP/TP01/P03/img/321ec853-941a-e69e-7fa1-eac7f318f366.png new file mode 100644 index 0000000000000000000000000000000000000000..b300b3db44c9291fcbf085907c3a7decc20b7baf Binary files /dev/null and b/TP/TP01/P03/img/321ec853-941a-e69e-7fa1-eac7f318f366.png differ diff --git a/TP/TP01/P03/img/343ed3f0-798d-32ed-eb69-f5b428471c19.png b/TP/TP01/P03/img/343ed3f0-798d-32ed-eb69-f5b428471c19.png new file mode 100644 index 0000000000000000000000000000000000000000..23da656ec16eadc9f5675587c57f2b9424a87e46 Binary files /dev/null and b/TP/TP01/P03/img/343ed3f0-798d-32ed-eb69-f5b428471c19.png differ diff --git a/TP/TP01/P03/img/4a0ff2c8-7524-5a5b-6e82-b37642bf6def.png b/TP/TP01/P03/img/4a0ff2c8-7524-5a5b-6e82-b37642bf6def.png new file mode 100644 index 0000000000000000000000000000000000000000..23feed0211d841efd9b9c73d382348a2f8f40071 Binary files /dev/null and b/TP/TP01/P03/img/4a0ff2c8-7524-5a5b-6e82-b37642bf6def.png differ diff --git a/TP/TP01/P03/img/4fb5ffee-c72d-a569-8ff7-c133d14386ed.png b/TP/TP01/P03/img/4fb5ffee-c72d-a569-8ff7-c133d14386ed.png new file mode 100644 index 0000000000000000000000000000000000000000..74db8c961b541871e7de6be496d35c53d3f336c3 Binary files /dev/null and b/TP/TP01/P03/img/4fb5ffee-c72d-a569-8ff7-c133d14386ed.png differ diff --git a/TP/TP01/P03/img/69e4196e-0ab1-2975-bcca-7ad56cb9f246.png b/TP/TP01/P03/img/69e4196e-0ab1-2975-bcca-7ad56cb9f246.png new file mode 100644 index 0000000000000000000000000000000000000000..bbcbe390c886d91a82afe8f12ab309e6a26184ff Binary files /dev/null and b/TP/TP01/P03/img/69e4196e-0ab1-2975-bcca-7ad56cb9f246.png differ diff --git a/TP/TP01/P03/img/8248ea8c-777a-3f5f-4441-4e7e65f06321.png b/TP/TP01/P03/img/8248ea8c-777a-3f5f-4441-4e7e65f06321.png new file mode 100644 index 0000000000000000000000000000000000000000..15a46083d07ff3bceae1ca7007c194801cd5bc49 Binary files /dev/null and b/TP/TP01/P03/img/8248ea8c-777a-3f5f-4441-4e7e65f06321.png differ diff --git a/TP/TP01/P03/img/88ed11b7-b2c8-fdc3-4433-c3a5f9400f6d.png b/TP/TP01/P03/img/88ed11b7-b2c8-fdc3-4433-c3a5f9400f6d.png new file mode 100644 index 0000000000000000000000000000000000000000..73284b03571c4c91522b120229921e8fd943c88e Binary files /dev/null and b/TP/TP01/P03/img/88ed11b7-b2c8-fdc3-4433-c3a5f9400f6d.png differ diff --git a/TP/TP01/P03/img/9e61a3ea-c0cf-ce23-4caa-ea8be8b8180d.png b/TP/TP01/P03/img/9e61a3ea-c0cf-ce23-4caa-ea8be8b8180d.png new file mode 100644 index 0000000000000000000000000000000000000000..184c7a280b9aaca34cb05860f1ab12dccb94bc74 Binary files /dev/null and b/TP/TP01/P03/img/9e61a3ea-c0cf-ce23-4caa-ea8be8b8180d.png differ diff --git a/TP/TP01/P03/img/cursor-pause.png b/TP/TP01/P03/img/cursor-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9c93cc142f4326a188eafc3c0fe96f2975dcab0c Binary files /dev/null and b/TP/TP01/P03/img/cursor-pause.png differ diff --git a/TP/TP01/P03/img/cursor.png b/TP/TP01/P03/img/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..5b4a20e63078ce18bb11a4e601a1994b261522ef Binary files /dev/null and b/TP/TP01/P03/img/cursor.png differ diff --git a/TP/TP01/P03/img/e198e134-62de-f434-c767-5c759618a866.png b/TP/TP01/P03/img/e198e134-62de-f434-c767-5c759618a866.png new file mode 100644 index 0000000000000000000000000000000000000000..2503f6e0d09087043e3615ae1e5b0cced2ad0fa7 Binary files /dev/null and b/TP/TP01/P03/img/e198e134-62de-f434-c767-5c759618a866.png differ diff --git a/TP/TP01/P03/img/edcbee3f-34e7-d5af-c956-28b9d0680a7b.png b/TP/TP01/P03/img/edcbee3f-34e7-d5af-c956-28b9d0680a7b.png new file mode 100644 index 0000000000000000000000000000000000000000..cba92a12052b130e626c1768aa4cbd2df781f617 Binary files /dev/null and b/TP/TP01/P03/img/edcbee3f-34e7-d5af-c956-28b9d0680a7b.png differ diff --git a/TP/TP01/P03/img/ee3f999c-8cdc-3624-ed00-917c9f8025b0.png b/TP/TP01/P03/img/ee3f999c-8cdc-3624-ed00-917c9f8025b0.png new file mode 100644 index 0000000000000000000000000000000000000000..67cc3bd3d236ee38f57d1d27502f4d602b72dd71 Binary files /dev/null and b/TP/TP01/P03/img/ee3f999c-8cdc-3624-ed00-917c9f8025b0.png differ diff --git a/TP/TP01/P03/img/f5a01d52-fc33-d9e0-2ddf-4ec7f9f4799f.png b/TP/TP01/P03/img/f5a01d52-fc33-d9e0-2ddf-4ec7f9f4799f.png new file mode 100644 index 0000000000000000000000000000000000000000..954c399b01c000298ebbf481a450fd1d1e83193d Binary files /dev/null and b/TP/TP01/P03/img/f5a01d52-fc33-d9e0-2ddf-4ec7f9f4799f.png differ diff --git a/TP/TP01/P03/img/f716c082-83a5-4cd2-1e69-4c66c05f2c48.png b/TP/TP01/P03/img/f716c082-83a5-4cd2-1e69-4c66c05f2c48.png new file mode 100644 index 0000000000000000000000000000000000000000..d94082e69a1b8faac4b5aebbe003799e265af3a5 Binary files /dev/null and b/TP/TP01/P03/img/f716c082-83a5-4cd2-1e69-4c66c05f2c48.png differ diff --git a/TP/TP01/P03/img/f7902f1c-c5d4-b6f3-23a9-0d3d21e8cf88.png b/TP/TP01/P03/img/f7902f1c-c5d4-b6f3-23a9-0d3d21e8cf88.png new file mode 100644 index 0000000000000000000000000000000000000000..4fdd6716793b13ba207f4a16a32613bddb91bab4 Binary files /dev/null and b/TP/TP01/P03/img/f7902f1c-c5d4-b6f3-23a9-0d3d21e8cf88.png differ diff --git a/TP/TP01/P03/index.html b/TP/TP01/P03/index.html new file mode 100644 index 0000000000000000000000000000000000000000..ce5660aa5c8f2e2d2a522ec6f5e759018a1dedd4 --- /dev/null +++ b/TP/TP01/P03/index.html @@ -0,0 +1,542 @@ +<!DOCTYPE html> + +<html lang="en"> + +<head> +<title>Dahu Presentation +</title> +<meta charset="utf-8"> +<script src="http://code.jquery.com/jquery-1.9.1.min.js" type="text/javascript"> +</script> +<script src="parse-search.js" type="text/javascript"> +</script> + +<link rel="stylesheet" href="dahuapp.viewer.css"><style>.s0-o2{background-color: #FFFFDD;width: 240px} +.s1-o2{background-color: #FFFFDD;width: 240px} +.s2-o2{background-color: #FFFFDD;width: 240px} +.s3-o2{background-color: #FFFFDD;width: 240px} +.s4-o2{background-color: #FFFFDD;width: 240px} +.s5-o2{background-color: #FFFFDD;width: 240px} +.s6-o2{background-color: #FFFFDD;width: 240px} +.s7-o2{background-color: #FFFFDD;width: 240px} +.s9-o2{background-color: #FFFFDD;width: 240px} +.s10-o2{background-color: #FFFFDD;width: 240px} +.s11-o2{background-color: #FFFFDD;width: 240px} +.s12-o2{background-color: #FFFFDD;width: 240px} +.s13-o2{background-color: #FFFFDD;width: 240px} +.s14-o2{background-color: #FFFFDD;width: 240px} +.s15-o2{background-color: #FFFFDD;width: 240px} +</style> +</head> + +<body> + +<div id="my-dahu-presentation"> + +<div id="loading">Loading presentation... +</div> + +<div class="object-list" style="display: none"> +<img src="img/69e4196e-0ab1-2975-bcca-7ad56cb9f246.png" alt="img/69e4196e-0ab1-2975-bcca-7ad56cb9f246.png" class="background 69e4196e-0ab1-2975-bcca-7ad56cb9f2460"> + +<div class="tooltip s0-o2">Sélectionner l'onglet Continuous dans la boite à outils Simulink. +</div> +<img src="img/4a0ff2c8-7524-5a5b-6e82-b37642bf6def.png" alt="img/4a0ff2c8-7524-5a5b-6e82-b37642bf6def.png" class="background 4a0ff2c8-7524-5a5b-6e82-b37642bf6def0"> + +<div class="tooltip s1-o2">Sélectionner le bloc Derivator. +</div> +<img src="img/f716c082-83a5-4cd2-1e69-4c66c05f2c48.png" alt="img/f716c082-83a5-4cd2-1e69-4c66c05f2c48.png" class="background f716c082-83a5-4cd2-1e69-4c66c05f2c480"> + +<div class="tooltip s2-o2">Déposer un bloc Derivator dans votre modèle. +</div> +<img src="img/f5a01d52-fc33-d9e0-2ddf-4ec7f9f4799f.png" alt="img/f5a01d52-fc33-d9e0-2ddf-4ec7f9f4799f.png" class="background f5a01d52-fc33-d9e0-2ddf-4ec7f9f4799f0"> + +<div class="tooltip s3-o2">Sélectionner le bloc Integrator. +</div> +<img src="img/88ed11b7-b2c8-fdc3-4433-c3a5f9400f6d.png" alt="img/88ed11b7-b2c8-fdc3-4433-c3a5f9400f6d.png" class="background 88ed11b7-b2c8-fdc3-4433-c3a5f9400f6d0"> + +<div class="tooltip s4-o2">Déposer un bloc Integrator dans votre modèle. +</div> +<img src="img/0edbde4a-26ff-f2d1-a88f-5a13affc536a.png" alt="img/0edbde4a-26ff-f2d1-a88f-5a13affc536a.png" class="background 0edbde4a-26ff-f2d1-a88f-5a13affc536a0"> + +<div class="tooltip s5-o2">Connecter l'entrée du bloc Derivator au signal de sortie du bloc Générateur de sinusoïde. +</div> +<img src="img/321ec853-941a-e69e-7fa1-eac7f318f366.png" alt="img/321ec853-941a-e69e-7fa1-eac7f318f366.png" class="background 321ec853-941a-e69e-7fa1-eac7f318f3660"> + +<div class="tooltip s6-o2">Connecter l'entrée du bloc Integrator au signal de sortie du bloc Générateur de sinusoïde. +</div> +<img src="img/edcbee3f-34e7-d5af-c956-28b9d0680a7b.png" alt="img/edcbee3f-34e7-d5af-c956-28b9d0680a7b.png" class="background edcbee3f-34e7-d5af-c956-28b9d0680a7b0"> + +<div class="tooltip s7-o2">Ouvrir les paramètres de l'écran de l'oscilloscope. +</div> +<img src="img/9e61a3ea-c0cf-ce23-4caa-ea8be8b8180d.png" alt="img/9e61a3ea-c0cf-ce23-4caa-ea8be8b8180d.png" class="background 9e61a3ea-c0cf-ce23-4caa-ea8be8b8180d0"> +<img src="img/1d9e476d-7d77-fc65-07f3-77174933ac05.png" alt="img/1d9e476d-7d77-fc65-07f3-77174933ac05.png" class="background 1d9e476d-7d77-fc65-07f3-77174933ac050"> + +<div class="tooltip s9-o2">Indiquer que l'oscilloscope doit avoir 3 entrées. +</div> +<img src="img/ee3f999c-8cdc-3624-ed00-917c9f8025b0.png" alt="img/ee3f999c-8cdc-3624-ed00-917c9f8025b0.png" class="background ee3f999c-8cdc-3624-ed00-917c9f8025b00"> + +<div class="tooltip s10-o2">Les 3 entrées apparaissent sur le bloc Oscilloscope. +</div> +<img src="img/8248ea8c-777a-3f5f-4441-4e7e65f06321.png" alt="img/8248ea8c-777a-3f5f-4441-4e7e65f06321.png" class="background 8248ea8c-777a-3f5f-4441-4e7e65f063210"> + +<div class="tooltip s11-o2">Connecter la sortie du bloc Derivator sur la deuxième entrée du bloc Oscilloscope. +</div> +<img src="img/01f96120-1e41-b4d3-b844-e73128943106.png" alt="img/01f96120-1e41-b4d3-b844-e73128943106.png" class="background 01f96120-1e41-b4d3-b844-e731289431060"> + +<div class="tooltip s12-o2">Connecter la sortie du bloc Integrator sur la troisième entrée du bloc Oscilloscope. +</div> +<img src="img/343ed3f0-798d-32ed-eb69-f5b428471c19.png" alt="img/343ed3f0-798d-32ed-eb69-f5b428471c19.png" class="background 343ed3f0-798d-32ed-eb69-f5b428471c190"> + +<div class="tooltip s13-o2">Retourner en simulation à pas variable (Variable step). +</div> +<img src="img/f7902f1c-c5d4-b6f3-23a9-0d3d21e8cf88.png" alt="img/f7902f1c-c5d4-b6f3-23a9-0d3d21e8cf88.png" class="background f7902f1c-c5d4-b6f3-23a9-0d3d21e8cf880"> + +<div class="tooltip s14-o2">Démarrer la simulation. +</div> +<img src="img/e198e134-62de-f434-c767-5c759618a866.png" alt="img/e198e134-62de-f434-c767-5c759618a866.png" class="background e198e134-62de-f434-c767-5c759618a8660"> + +<div class="tooltip s15-o2">Mettre à l'échelle l'écran de l'oscilloscope. Observer les résultats obtenus pour la dérivation et l'intégration d'une fonction sinusoïde. +</div> + +<div class="mouse-cursor"> +<img src="img/cursor.png" alt="img/cursor.png" class="mouse-cursor-normal"> +<img src="img/cursor-pause.png" alt="img/cursor-pause.png" style="display: none" class="mouse-cursor-pause"> +</div> +</div> + +<div class="control" style="top: 616px;"> +<button class="previous">Previous +</button> +<button class="next">Next +</button> +</div> +</div> +<script src="dahuapp.js" type="text/javascript"> +</script> +<script src="dahuapp.viewer.js" type="text/javascript"> +</script> +<script type="text/javascript">(function($) { + var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams); + myPresentation.load({ + "metaData": { + "imageWidth": 800, + "imageHeight": 600, + "initialBackgroundId": "69e4196e-0ab1-2975-bcca-7ad56cb9f2460", + "initialMouseX": 0.6715277777777777, + "initialMouseY": 0.18222222222222223 + }, + "action": [ + { + "id": "37", + "type": "appear", + "target": "s0-o2", + "trigger": "afterPrevious", + "abs": 0.35833333333333334, + "ord": 0.11625, + "duration": 400 + }, + { + "id": "3", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.775, + "finalOrd": 0.17, + "speed": 0.8 + }, + { + "id": "4", + "type": "appear", + "target": "4a0ff2c8-7524-5a5b-6e82-b37642bf6def0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "38", + "type": "appear", + "target": "s1-o2", + "trigger": "afterPrevious", + "abs": 0.3933333333333333, + "ord": 0.11625, + "duration": 400 + }, + { + "id": "5", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.25, + "finalOrd": 0.3477777777777778, + "speed": 0.8 + }, + { + "id": "6", + "type": "appear", + "target": "f716c082-83a5-4cd2-1e69-4c66c05f2c480", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "39", + "type": "appear", + "target": "s2-o2", + "trigger": "afterPrevious", + "abs": 0.17833333333333334, + "ord": 0.1675, + "duration": 400 + }, + { + "id": "7", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.9041666666666667, + "finalOrd": 0.17444444444444446, + "speed": 0.8 + }, + { + "id": "8", + "type": "appear", + "target": "f5a01d52-fc33-d9e0-2ddf-4ec7f9f4799f0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "40", + "type": "appear", + "target": "s3-o2", + "trigger": "afterPrevious", + "abs": 0.405, + "ord": 0.105, + "duration": 400 + }, + { + "id": "9", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.24375, + "finalOrd": 0.45111111111111113, + "speed": 0.8 + }, + { + "id": "10", + "type": "appear", + "target": "88ed11b7-b2c8-fdc3-4433-c3a5f9400f6d0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "41", + "type": "appear", + "target": "s4-o2", + "trigger": "afterPrevious", + "abs": 0.26666666666666666, + "ord": 0.17125, + "duration": 400 + }, + { + "id": "11", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.21736111111111112, + "finalOrd": 0.2633333333333333, + "speed": 0.8 + }, + { + "id": "12", + "type": "appear", + "target": "0edbde4a-26ff-f2d1-a88f-5a13affc536a0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "42", + "type": "appear", + "target": "s5-o2", + "trigger": "afterPrevious", + "abs": 0.25833333333333336, + "ord": 0.13375, + "duration": 400 + }, + { + "id": "13", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.21666666666666667, + "finalOrd": 0.3511111111111111, + "speed": 0.8 + }, + { + "id": "14", + "type": "appear", + "target": "321ec853-941a-e69e-7fa1-eac7f318f3660", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "43", + "type": "appear", + "target": "s6-o2", + "trigger": "afterPrevious", + "abs": 0.27, + "ord": 0.1425, + "duration": 400 + }, + { + "id": "31", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.06597222222222222, + "finalOrd": 0.6666666666666666, + "speed": 0.8 + }, + { + "id": "32", + "type": "appear", + "target": "edcbee3f-34e7-d5af-c956-28b9d0680a7b0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "44", + "type": "appear", + "target": "s7-o2", + "trigger": "afterPrevious", + "abs": 0.12, + "ord": 0.2975, + "duration": 400 + }, + { + "id": "15", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.06388888888888888, + "finalOrd": 0.6666666666666666, + "speed": 0.8 + }, + { + "id": "16", + "type": "appear", + "target": "9e61a3ea-c0cf-ce23-4caa-ea8be8b8180d0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "17", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.09444444444444444, + "finalOrd": 0.7566666666666667, + "speed": 0.8 + }, + { + "id": "18", + "type": "appear", + "target": "1d9e476d-7d77-fc65-07f3-77174933ac050", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "45", + "type": "appear", + "target": "s9-o2", + "trigger": "afterPrevious", + "abs": 0.14833333333333334, + "ord": 0.315, + "duration": 400 + }, + { + "id": "19", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3013888888888889, + "finalOrd": 0.37, + "speed": 0.8 + }, + { + "id": "20", + "type": "appear", + "target": "ee3f999c-8cdc-3624-ed00-917c9f8025b00", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "46", + "type": "appear", + "target": "s10-o2", + "trigger": "afterPrevious", + "abs": 0.315, + "ord": 0.10125, + "duration": 400 + }, + { + "id": "21", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.25763888888888886, + "finalOrd": 0.24555555555555555, + "speed": 0.8 + }, + { + "id": "22", + "type": "appear", + "target": "8248ea8c-777a-3f5f-4441-4e7e65f063210", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "47", + "type": "appear", + "target": "s11-o2", + "trigger": "afterPrevious", + "abs": 0.2816666666666667, + "ord": 0.125, + "duration": 400 + }, + { + "id": "23", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.30416666666666664, + "finalOrd": 0.2777777777777778, + "speed": 0.8 + }, + { + "id": "24", + "type": "appear", + "target": "01f96120-1e41-b4d3-b844-e731289431060", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "48", + "type": "appear", + "target": "s12-o2", + "trigger": "afterPrevious", + "abs": 0.31, + "ord": 0.10875, + "duration": 400 + }, + { + "id": "25", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.56875, + "finalOrd": 0.7166666666666667, + "speed": 0.8 + }, + { + "id": "26", + "type": "appear", + "target": "343ed3f0-798d-32ed-eb69-f5b428471c190", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "49", + "type": "appear", + "target": "s13-o2", + "trigger": "afterPrevious", + "abs": 0.3333333333333333, + "ord": 0.31625, + "duration": 400 + }, + { + "id": "27", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2916666666666667, + "finalOrd": 0.10111111111111111, + "speed": 0.8 + }, + { + "id": "28", + "type": "appear", + "target": "f7902f1c-c5d4-b6f3-23a9-0d3d21e8cf880", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "50", + "type": "appear", + "target": "s14-o2", + "trigger": "afterPrevious", + "abs": 0.2966666666666667, + "ord": 0.1275, + "duration": 400 + }, + { + "id": "29", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.14791666666666667, + "finalOrd": 0.6666666666666666, + "speed": 0.8 + }, + { + "id": "30", + "type": "appear", + "target": "e198e134-62de-f434-c767-5c759618a8660", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "51", + "type": "appear", + "target": "s15-o2", + "trigger": "afterPrevious", + "abs": 0.20833333333333334, + "ord": 0.27375, + "duration": 400 + } + ] +}); + myPresentation.start(); +})(jQuery); + +</script> +</body> +</html> \ No newline at end of file diff --git a/TP/TP01/P03/parse-search.js b/TP/TP01/P03/parse-search.js new file mode 100644 index 0000000000000000000000000000000000000000..e7d01c07f6a5d45b9fcabd5d271a8c6cfc5f00e2 --- /dev/null +++ b/TP/TP01/P03/parse-search.js @@ -0,0 +1,14 @@ +// Adapted from http://stackoverflow.com/questions/3234125/creating-array-from-window-location-hash +(function () { + var search = window.location.search.slice(1); + var array = search.split("&"); + + var values, form_data = {}; + + for (var i = 0; i < array.length; i += 1) { + values = array[i].split("="); + form_data[values[0]] = unescape(values[1]); + } + window.getParams = form_data; +}()) + diff --git a/TP/TP01/P04/dahuapp.js b/TP/TP01/P04/dahuapp.js new file mode 100644 index 0000000000000000000000000000000000000000..41c69e9169345a9a6703325d5557a4cc36913e19 --- /dev/null +++ b/TP/TP01/P04/dahuapp.js @@ -0,0 +1,880 @@ +"use strict"; + +/** + * Dahuapp core module. + * + * @param window window javascript object. + * @param $ jQuery + * @returns dahuapp core module. + */ +(function (window, $) { + var dahuapp = (function () { + + var self = {}; + + /* private API */ + + var DahuScreencastGenerator = function () { + + /* + * Format the specified string in a readable format. + */ + function htmlFormat(htmlString) { + var i; + var readableHTML = htmlString; + var lb = '\n'; + var htags = ["<html", "</html>", "</head>", "<title", "</title>", "<meta", "<link", "</body>"]; + for (i = 0; i < htags.length; ++i) { + var hhh = htags[i]; + readableHTML = readableHTML.replace(new RegExp(hhh, 'gi'), lb + hhh); + } + var btags = ["</div>", "</section>", "</span>", "<br>", "<br />", "<blockquote", "</blockquote>", "<ul", "</ul>", "<ol", "</ol>", "<li", "<\!--", "<script", "</script>"]; + for (i = 0; i < btags.length; ++i) { + var bbb = btags[i]; + readableHTML = readableHTML.replace(new RegExp(bbb, 'gi'), lb + bbb); + } + var ftags = ["<img", "<legend", "</legend>", "<button", "</button>"]; + for (i = 0; i < ftags.length; ++i) { + var fff = ftags[i]; + readableHTML = readableHTML.replace(new RegExp(fff, 'gi'), lb + fff); + } + var xtags = ["<body", "<head", "<div", "<section", "<span", "<p"]; + for (i = 0; i < xtags.length; ++i) { + var xxx = xtags[i]; + readableHTML = readableHTML.replace(new RegExp(xxx, 'gi'), lb + lb + xxx); + } + return readableHTML; + } + + /* + * Generates the html header. + */ + var generateHtmlHeader = function ($generated, cssGen) { + $('head', $generated) + .append($(document.createElement('title')) + .append("Dahu Presentation"))/* TODO: make this customizable */ + .append($(document.createElement('meta')) + .attr({'charset': 'utf-8'})) + .append($(document.createElement('script')) + .attr({'src': 'http://code.jquery.com/jquery-1.9.1.min.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'parse-search.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('link')) + .attr({'rel': 'stylesheet', 'href': 'dahuapp.viewer.css'})) + .append($(document.createElement('style')) + .append(cssGen)); + }; + + /* + * Generates the objects. + */ + + var generateHtmlBackgroundImage = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('img')) + .attr({'src': object.img, 'alt': object.img, 'class': 'background ' + object.id})); + }; + var generateHtmlTooltip = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'tooltip ' + object.id}) + .append(object.text)); + }; + + var generateCssTooltip = function ($generated, object) { + var style = []; + + if( object.color != null ) { + style.push('background-color: ' + object.color); + } + if( object.width != null ) { + style.push('width: ' + object.width); + } + + if( style.length != 0 ) { + $generated.append( + '.' + object.id + '{' + style.join(';') + '}\n'); + } + + return $generated; + }; + + /* + * Returns the code used to call the viewer to the presentation. + */ + var getBasicCallCode = function (jsonModel) { + var code = '(function($) {\n'; + code += ' var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams);\n'; + code += ' myPresentation.load(' + jsonModel + ');\n'; + code += ' myPresentation.start();\n'; + code += '})(jQuery);\n'; + return code; + }; + + /* + * Generates the html body. + */ + var generateHtmlBody = function ($generated, jsonModel, jsonGen) { + $('body', $generated) + /* We could use a <section> here too, but it does not work with MS IE 8. + Alternatively, adding this in the header would work: + + <!--[if lt IE 9]> + <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + */ + .append($(document.createElement('div')) + .attr({'id': 'my-dahu-presentation'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.viewer.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'type': 'text/javascript'}) + .append(getBasicCallCode(jsonGen))); + $('#my-dahu-presentation', $generated) + .append($(document.createElement('div')) + .attr({'id': 'loading'}).append("Loading presentation...")) + .append($(document.createElement('div')) + .attr({'class': 'object-list', + 'style': 'display: none'})) + .append($(document.createElement('div')) + .attr({'class': 'control'})); + + /* Adding the objects to the page */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "background": + generateHtmlBackgroundImage($generated, object); + break; + case "tooltip": + generateHtmlTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + /* Warning here, i'm not sure if $.each is always over, here */ + + /* Adding the control buttons to the page */ + $('.control', $generated) + .css({'top': (jsonModel.getImageHeight() + 16) + 'px'}) + .append($(document.createElement('button')) + .attr({'class': 'previous'}) + .append('Previous')) + .append($(document.createElement('button')) + .attr({'class': 'next'}) + .append('Next')); + + /* Adding the mouse cursor image */ + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'mouse-cursor'}) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor.png', 'alt': 'img/cursor.png', 'class': 'mouse-cursor-normal'})) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor-pause.png', 'alt': 'img/cursor-pause.png', + 'style': 'display: none', 'class': 'mouse-cursor-pause'}))); + }; + + /* + * Generates the css String with the Json model. + */ + this.generateCssString = function (jsonModel) { + var $generated = $('<style></style>'); + + /* Going through each object */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "tooltip": + generateCssTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + return $generated.text(); + } + + /* + * Generates the html String with the Json model. + */ + this.generateHtmlString = function (jsonModel, jsonGen, cssGen) { + /* Initialising the compilation area */ + var $generated = $(document.createElement('div')); + + /* We create the html using the json */ + $generated.append($(document.createElement('html')) + .attr({'lang': 'en'})); + $('html', $generated) + .append($(document.createElement('head'))) + .append($(document.createElement('body'))); + + generateHtmlHeader($generated, cssGen); + generateHtmlBody($generated, jsonModel, jsonGen); + + var result = htmlFormat($generated.html()); + + return '<!DOCTYPE html>\n' + result; + }; + + /* + * Generates the generated JSON using the JSONmodel. + * @param {object} jsonModel The json model to transform. + * @param {java.awt.Dimension} imgDim The dimension of images. + */ + this.generateJsonString = function (jsonModel, imgDim) { + var generated = self.createScreencastGeneratedModel(); + generated.setImageSize(imgDim.width, imgDim.height); + generated.setInitialBackground(jsonModel.getInitialBackground()); + generated.setInitialMousePos(jsonModel.getInitialMousePos()); + for (var i = 0; i < jsonModel.getNbSlide(); i++) { + var actionList = jsonModel.getActionList(i); + for (var j = 0; j < actionList.length; j++) { + /* + * We don't add the two first actions of the first slide + * because they are present in the presentation metadata. + * It corresponds to the mouse initial pos and first background. + */ + if (i > 0 || j > 1) { + generated.addAction(actionList[j], imgDim.width, imgDim.height); + } + } + } + return generated.getJson(); + }; + }; + + /* + * Model for a JSON object that will only be used by the viewer, never + * saved on a file, used to transform the properties of actions + * specified on the JSON file of a presentation to executable + * functions for each action. + */ + var DahuScreencastExecutableModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* + * Creates a functions representing the specified action, and adds + * it to this object. + * @param {object} action + */ + var addExecutableAction = function (action) { + var executableAction = { + 'id': action.id, + 'trigger': action.trigger, + 'target': action.target, + 'delayAfter': action.delayAfter, + 'doneFunction': function (events, selector) { + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.delayAfter); + } + }; + if (executableAction.delayAfter == null) { + executableAction.delayAfter = 200; + } + switch (action.type.toLowerCase()) { + case "appear": + executableAction.abs = (action.abs * json.metaData.imageWidth) + 'px'; + executableAction.ord = (action.ord * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(); + }; + break; + case "disappear": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + $(selector + ' .' + this.target).hide(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).show(); + }; + executableAction.executeImmediately = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + break; + case "move": + executableAction.finalAbs = (action.finalAbs * json.metaData.imageWidth) + 'px'; + executableAction.finalOrd = (action.finalOrd * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.speed = action.speed; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + if (this.duration == null) { + var initialAbsPix = this.initialAbs.replace('px', ''); + var initialOrdPix = this.initialOrd.replace('px', ''); + var finalAbsPix = this.finalAbs.replace('px', ''); + var finalOrdPix = this.finalOrd.replace('px', ''); + var distance = Math.sqrt(Math.pow(finalAbsPix - initialAbsPix, 2) + + Math.pow(finalOrdPix - initialOrdPix, 2)); + if (!this.speed) { + this.speed = .8; // in pixel per milisecond: fast, but not too much. + } + this.duration = distance + this.speed; + if (this.duration < 200) { // Slow down a bit for short distances. + this.duration = 200; + } + } + $(sel).animate({ + 'left': this.finalAbs, + 'top': this.finalOrd + }, this.duration, 'linear', function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).css({ + 'left': this.initialAbs, + 'top': this.initialOrd + }); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + $(sel).css({ + 'left': this.finalAbs, + 'top': this.finalOrd + }); + }; + break; + case "delay": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.duration); + }; + executableAction.executeReverse = function (selector) { + // Nothing! + }; + executableAction.executeImmediately = function (selector) { + // Nothing too! + }; + break; + } + json.action.push(executableAction); + }; + + /* Public API */ + + /* + * Loads the specified JSON read from a 'presentation.json' file, + * and stores the functions representing each actions in an object. + * @param {object} jsonToLoad + */ + this.loadJson = function (jsonToLoad) { + json.metaData = jsonToLoad.metaData; + for (var i = 0; i < jsonToLoad.action.length; i++) { + addExecutableAction(jsonToLoad.action[i]); + } + }; + + /* + * Returns the object containing the functions. + */ + this.getJson = function () { + return json; + }; + }; + + /* + * Used to transform the 'dahu' file to a JSON file used by the viewer, + * which only contains some metaData and a list of actions. + */ + var DahuScreencastGeneratedModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* Public API */ + + /* + * Returns a string representation of this json. + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * Setters for the generated json metadata. + */ + this.setImageSize = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + this.setInitialMousePos = function (pos) { + json.metaData.initialMouseX = pos.x; + json.metaData.initialMouseY = pos.y; + }; + + this.setInitialBackground = function (id) { + json.metaData.initialBackgroundId = id; + }; + + this.addAction = function (action) { + json.action.push(action); + }; + + /* + * Transforms a JSON containing action properties to a JSON containing + * the execution functions. + * @param {Object} json + * @returns {Object} A json object containing the execution functions + * for all the actions of the presentation. + */ + this.toExecutableList = function (json) { + var executableList = { + metaData: json.metaData, + action: new Array() + }; + for (var i = 0; i < json.action.length; i++) { + addExecutableAction(executableList, json.action[i]); + } + return executableList; + }; + }; + + /* + * Represents a 'dahu' file for a project. + */ + var DahuScreencastModel = function () { + + /* Private API */ + + var json = {}; + + /* + * Generates a unique action ID. + * + * With this implementation, this ID is unique as long as the user + * doesn't replace it manually with a not kind value or replace + * the nextUniqueId with bad intentions. + * But maybe that a UUID is a bit tiresome to put as an anchor... + */ + var generateUniqueActionId = function () { + json.metaData.nextUniqueId++; + return json.metaData.nextUniqueId.toString(); + }; + + /* + * This method checks if the json representing a dahu project is + * in the good version. It's in case a project file was created + * with a previous version of Dahu, and that some fields are + * missing. + * + * It doesn't control each field (at the moment) but only the + * fields that can be missing due to a new Dahu version and not + * to a manual editing. + * + * This method doesn't check any Json syntax or something like that. + */ + var upgradeJsonVersion = function () { + // Checks if unique IDs are in the project file + if (!json.metaData.nextUniqueId) { + var currentId = 0; + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].action.length; j++) { + json.data[i].action[j].id = currentId.toString(); + currentId++; + } + } + json.metaData.nextUniqueId = currentId; + } + }; + + /* Public API */ + + /* + * json variable generated from a JSON file. + * @param String stringJson String loaded from JSON file. + */ + this.loadJson = function (stringJson) { + json = JSON.parse(stringJson); + upgradeJsonVersion(); + }; + + /* + * Create a new presentation variable in the JSON file which will contain slides. + */ + this.createPresentation = function (width, height) { + json.metaData = {}; + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + json.metaData.nextUniqueId = 0; + json.data = new Array(); + }; + + /* + * Add a new slide in the presentation variable of the JSON file. + * @param int index wanted for the slide. + * @param String idSlide Unique identifier for the slide. + * @param String img Related to pathname of the image. + * @param double mouseX Abscissa mouse position in %. + * @param double mouseY Ordinate mouse position in %. + * @return Index of the newly added slide. + */ + this.addSlide = function (indexSlide, idSlide, img, mouseX, mouseY, speed) { + var slide = { + "object": new Array(), + "action": new Array() + }; + json.data.splice(indexSlide, 0, slide); + this.addObject(indexSlide, "background", idSlide, img); + this.addObject(indexSlide, "mouse"); + this.addAction(indexSlide, "move", json.data[indexSlide].object[1].id, "onClick", mouseX, mouseY, speed); + this.addAction(indexSlide, "appear", json.data[indexSlide].object[0].id, "afterPrevious"); + }; + + /* + * Object factory. + * Add a new Object in the slide idSlide. + * @param int idSlide + * @param string type + * Other params can be specified depending on the object's type. + */ + this.addObject = function (idSlide, type) { + var object = { + "type": type + }; + switch (type.toLowerCase()) { + case "background": + object.id = arguments[2] + json.data[idSlide].object.length; + object.img = arguments[3] || ""; + break; + case "mouse": + object.id = "mouse-cursor"; + break; + case "tooltip": + /* + * TODO: we'll need a more robust unique name + * when we start actually using this. + */ + object.id = "s" + idSlide + "-o" + json.data[idSlide].object.length; + object.text = arguments[2] || ""; + object.color = arguments[3] || null; + object.width = arguments[4] || ""; + json.data[idSlide].object.push(object); + var objectLength = json.data[idSlide].object.length; + var last = json.data[idSlide].object[objectLength-1]; + json.data[idSlide].object[objectLength-1] = + json.data[idSlide].object[objectLength-2]; + json.data[idSlide].object[objectLength-2] = last; + break; + } + if(type.toLowerCase() != "tooltip"){ + json.data[idSlide].object.push(object); + } + }; + + /* + * Action factory. + * Add a new Action in the slide idSlide whose target is the id of an object. + * Three types of trigger : "withPrevious", "afterPrevious", "onClick". + * @param int idSlide + * @param string type + * @param string target + * @param string trigger + * Other params can be specified depending on the object's type. + */ + this.addAction = function (idSlide, type, target, trigger) { + var action = { + "id": generateUniqueActionId(), + "type": type, + "target": target, + "trigger": trigger + }; + switch (type.toLowerCase()) { + case "appear": + action.abs = arguments[4] || 0.0; + action.ord = arguments[5] || 0.0; + action.duration = arguments[6] || 0; + break; + case "disappear": + action.duration = arguments[4] || 0; + break; + case "move": + action.finalAbs = arguments[4] || 0.0; + action.finalOrd = arguments[5] || 0.0; + action.speed = arguments[6] || 0; + break; + } + json.data[idSlide].action.push(action); + }; + + this.editMouse = function (idSlide, idAction, mouseX, mouseY) { + json.data[idSlide].action[idAction].finalAbs = mouseX; + json.data[idSlide].action[idAction].finalOrd = mouseY; + }; + + /* + * Sets a title for the presentation. + * @param String title Title to set. + */ + this.setTitle = function (title) { + json.metaData.title = title; + }; + + /* + * Sets an annotation for the presentation. + * @param String annotation Annotation to set. + */ + this.setAnnotation = function (annotation) { + json.metaData.annotation = annotation; + }; + + /* + * Inverts the two slides (their positions on the table). + * @param int idSlide1 Index of the first slide. + * @param int idSlide2 Index of the second slide. + */ + this.invertSlides = function (idSlide1, idSlide2) { + var tmp = json.data[idSlide1]; + json.data[idSlide1] = json.data[idSlide2]; + json.data[idSlide2] = tmp; + }; + + /* + * Inverts the two actions (their positions on the table). + * @param int idSlide + * @param int idAction1 + * @param int idAction2 + */ + this.invertActions = function (idSlide, idAction1, idAction2) { + var tmp = json.data[idSlide].action[idAction1]; + json.data[idSlide].action[idAction1] = json.data[idSlide].action[idAction2]; + json.data[idSlide].action[idAction2] = tmp; + }; + + /* + * Returns the actions on the specified slide. + * @returns {Array} + */ + this.getActionList = function (idSlide) { + return json.data[idSlide].action; + }; + + /* + * Catches all the objects of the presentation + * @returns {Array} List of objects of the presentation + */ + this.getObjectList = function () { + var objectList = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + var indexObject = 0; + while (json.data[indexSlide].object[indexObject]) { + objectList.push(json.data[indexSlide].object[indexObject]); + indexObject++; + } + indexSlide++; + } + return objectList; + }; + + /* + * Returns an array containing all the background images. + * @returns {Array} List of background images. + */ + this.getImageList = function () { + var list = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + list.push(json.data[indexSlide].object[0].img); + indexSlide++; + } + ; + return list; + }; + + /* + * Returns an object containing the id of the first background. + * @returns {string} Id of the first background. + */ + this.getInitialBackground = function () { + return json.data[0].object[0].id; + }; + + /* + * Returns an object containing the initial mouse position. + * @returns {object} Initial position of mouse. + */ + this.getInitialMousePos = function () { + var pos = {}; + pos.x = json.data[0].action[0].finalAbs; + pos.y = json.data[0].action[0].finalOrd; + return pos; + }; + + /* + * Removes the slide at the specified index. + * @param {int} idSlide + */ + this.removeSlide = function (idSlide) { + json.data.splice(idSlide, 1); + }; + + /* + * Removes the action at the specified slide. + * @param {int} idSlide + * @param {int} idAction + */ + this.removeAction = function (idSlide, idAction) { + json.data[idSlide].action.splice(idAction, 1); + }; + + /* + * Removes the specified object from the slide. + * Also removes all the actions attached to this object. + * @param {int} idSlide + * @param {int} idObject + */ + this.removeObject = function (idSlide, idObject) { + var removed = json.data[idSlide].object.splice(idObject, 1); + for (var i = 0; i < json.data.length; i++) { + var j = 0; + while (json.data[i].action[j]) { + if (json.data[i].action[j].target === removed.id) { + json.data[i].action.splice(j, 1); + } else { + j++; + } + } + } + }; + + /* + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * @returns {String} returns the index for the next slide. + */ + this.getNbSlide = function () { + return json.data.length; + }; + + /* + * @return {object} returns the object identified by idSlide + */ + this.getSlide = function (idSlide) { + return json.data[idSlide]; + }; + + /* + * Sets the size of images for the generated presentation. + * The parameters can be null : it means there are no + * requirement for this dimension. + * @param {int} width New width for the generated images. + * @param {int} height New height for the generated images. + */ + this.setImageSizeRequirements = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + /* + * Gets the width of images for the generated presentation. + * @return {int or null} Width of generated images. + */ + this.getImageWidth = function () { + return json.metaData.imageWidth; + }; + + /* + * Gets the height of images for the generated presentation. + * @return {int or null} Height of generated images. + */ + this.getImageHeight = function () { + return json.metaData.imageHeight; + }; + + /* + * Gets a background image (no one in particular, the first met). + * @return {string} The name of a background image. + */ + this.getABackgroundImage = function () { + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].object.length; j++) { + if (json.data[i].object[j].type === "background") { + return json.data[i].object[j].img; + } + } + } + return null; + }; + }; + + /* public API */ + + self.version = "0.0.1"; + + self.createScreencastGenerator = function createScreencastGenerator() { + return new DahuScreencastGenerator(); + }; + + self.createScreencastModel = function createScreencastModel() { + return new DahuScreencastModel(); + }; + + self.createScreencastExecutableModel = function createScreencastExecutableModel() { + return new DahuScreencastExecutableModel(); + }; + + self.createScreencastGeneratedModel = function createScreencastGeneratedModel() { + return new DahuScreencastGeneratedModel(); + }; + + return self; + })(); + + window.dahuapp = dahuapp; + +})(window, jQuery); \ No newline at end of file diff --git a/TP/TP01/P04/dahuapp.viewer.css b/TP/TP01/P04/dahuapp.viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ea934576dad6ca9263a6163de58f5fe4534d1f0b --- /dev/null +++ b/TP/TP01/P04/dahuapp.viewer.css @@ -0,0 +1,25 @@ +.object-list { + position: absolute; + margin: 0px; + padding: 0px; +} + +.mouse-cursor { + position: absolute; +} + +.control { + position: relative; +} + +.background { + position: absolute; +} + +.tooltip { + position: absolute; + width: 100px; + padding: 4px; + margin: 2px; + border: 2px black solid; +} \ No newline at end of file diff --git a/TP/TP01/P04/dahuapp.viewer.js b/TP/TP01/P04/dahuapp.viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..12ad03b2cdc503a8fd6ff3f5fdc2a74edbb36edb --- /dev/null +++ b/TP/TP01/P04/dahuapp.viewer.js @@ -0,0 +1,456 @@ +"use strict"; + +/** + * Dahuapp viewer module. + * + * @param dahuapp dahuapp object to augment with module. + * @param $ jQuery + * @returns dahuapp extended with viewer module. + */ + +(function(dahuapp, $) { + var viewer = (function() { + + var self = {}; + + var DahuViewerModel = function(select, getParams) { + + /* Private API */ + + var json = null; + var selector = select; + var parseAutoOption = function(name, defaultValue) { + var res = getParams[name]; + if (res == null) { + if (name == 'auto') { + return false; + } else { + return parseAutoOption('auto', defaultValue); + } + } + if (res.toLowerCase() === 'false') { + return false; + } + res = parseInt(res); + if (isNaN(res)) { + // e.g. ?autoplay or ?autoplay=true + return defaultValue; + } + return res; + } + + /* Whether to wait for "next" event between actions */ + var autoPlay = parseAutoOption('autoplay', 5000); + /* Whether to wait for "next" event on page load */ + var autoStart = parseAutoOption('autostart', 5000); + /* Whether to loop back to start at the end of presentation */ + var autoLoop = parseAutoOption('autoloop', 5000); + + var events = (function() { + var self = {}; + /* + * Creates a generic event. + */ + var createEvent = function() { + var callbacks = $.Callbacks(); + return { + publish: callbacks.fire, + subscribe: callbacks.add, + unsubscribe: callbacks.remove, + unsubscribeAll: callbacks.empty + }; + }; + /* + * Called when the button next is pressed. + */ + self.onNext = createEvent(); + /* + * Called when the button previous is pressed. + */ + self.onPrevious = createEvent(); + /* + * Called when an action is over. + */ + self.onActionOver = createEvent(); + /* + * Called when an action starts. + */ + self.onActionStart = createEvent(); + /* + * Called when at least one action was running and has finished. + */ + self.onAllActionFinish = createEvent(); + + return self; + })(); + + /* + * Variables used like index for methodes subscribed. + */ + var currentAction = 0; /* Action currently running */ + var nextAction = 0; /* Action to execute on 'Next' click */ + var nbActionsRunning = 0; + var previousAnchor = -1; /* Last entered anchor, only used in + * case the 'onhashchange' event is + * not supported by the web browser */ + + /* + * Functions to reinitialise running actions and subscribed + * callbacks (reinitialise is called once without stopping + * all the actions, so the two functions are separated). + */ + var stopAllActions = function() { + $(selector + " .object-list").children().stop(true, true); + reinitialiseCallbackLists(); + nbActionsRunning = 0; + }; + var reinitialiseCallbackLists = function() { + events.onActionStart.unsubscribeAll(); + events.onActionStart.subscribe(onActionStartEventHandler); + events.onAllActionFinish.unsubscribeAll(); + }; + + /* + * Timer used to program onNext event in autoplay mode. + */ + var playTimer = 0; + + /* + * Function used when an "onNextEvent" event is caught. + */ + var onNextEventHandler = function() { + /* + * If the user pressed "next" before an autoplay event + * is triggered, it replaces the autoplay event, hence + * cancels it: + */ + window.clearTimeout(playTimer); + + enterAnimationMode(); + stopAllActions(); + var tmpAction = nextAction; + var onlyWithPrevious = true; + nextAction++; + currentAction = nextAction; + while (json.action[currentAction] && onlyWithPrevious) { + switch (json.action[currentAction].trigger) { + case 'onClick': + nextAction = currentAction; + onlyWithPrevious = false; + break; + case 'withPrevious': + var tmp = currentAction; + /* + * We can't directly pass 'execute' as callback because we + * allow the 'execute' function to reference a property of the + * object (by using 'this.property') so we have to call the + * function in the containing object to make that available + */ + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + while (json.action[nextAction] && json.action[nextAction].trigger !== 'onClick') { + nextAction++; + } + onlyWithPrevious = false; + break; + } + currentAction++; + } + if (json.action[tmpAction]) { + launch(json.action[tmpAction]); + } + if (nextAction > json.action.length) { + nextAction = json.action.length; + } + }; + + /* + * Function used when an "onPreviousEvent" event is caught. + */ + var onPreviousEventHandler = function() { + stopAllActions(); + currentAction = nextAction - 1; + while (json.action[currentAction] && json.action[currentAction].trigger !== 'onClick') { + launchReverse(json.action[currentAction]); + currentAction--; + } + /* currentAction = -1 means that it's the beginning */ + if (currentAction > -1) { + launchReverse(json.action[currentAction]); + } + if (currentAction < 0) { + currentAction = 0; + } + nextAction = currentAction; + }; + + /* + * Function used when an "onActionOverEvent" event is caught. + */ + var onActionOverEventHandler = function() { + nbActionsRunning--; + if (nbActionsRunning === 0) { + events.onAllActionFinish.publish(events, selector); + reinitialiseCallbackLists(); + while (json.action[currentAction]) { + switch (json.action[currentAction].trigger) { + case 'onClick': + leaveAnimationMode(); + if (autoPlay && nbActionsRunning === 0) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoPlay); + } + return; + case 'withPrevious': + var tmp = currentAction; + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + currentAction++; + return; + } + currentAction++; + + } + if (autoLoop && nbActionsRunning === 0) { + setTimeout(function () { + resetPresentation(); + startPresentationMaybe(); + }, autoLoop); + } + } + leaveAnimationMode(); + }; + + /* + * Function used when an "onActionStartEvent" event is caught. + */ + var onActionStartEventHandler = function() { + nbActionsRunning++; + }; + + /* + * Enter and leave "animation" mode. The viewer is in + * animation mode when something is going on without human + * interaction (i.e. executing actions before the next + * "onClick"). + */ + var enterAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').hide(); + $(selector + ' .mouse-cursor-normal').show(); + }; + + var leaveAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').show(); + $(selector + ' .mouse-cursor-normal').hide(); + }; + + /* + * Function used to perform actions. + */ + var launch = function(action) { + action.execute(events, selector); + }; + var launchReverse = function(action) { + action.executeReverse(selector); + }; + + /* + * The two following methods each returns an array containing the + * actions to execute to reach the given anchor (respectively + * forward or backwards). + * + * If the given anchor matches none of the actions, then an empty + * array is returned. + */ + var getActionsToJumpForward = function(anchor) { + var actions = new Array(); + for (var i = nextAction; i < json.action.length; i++) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + if (json.action[i].id == anchor) { + return actions; + } else { + actions.push(json.action[i]); + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + var getActionsToJumpBackwards = function(anchor) { + var actions = new Array(); + for (var i = nextAction - 1; i >= 0; i--) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + actions.push(json.action[i]); + if (json.action[i].id == anchor) { + return actions; + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + + /* + * Updates the position of the presentation depending on the + * given anchor (next action wanted). + */ + var jumpToAnchor = function(anchor) { + if (anchor !== '') { + stopAllActions(); + if (anchor > nextAction) { + // forward + var actions = getActionsToJumpForward(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeImmediately(selector); + } + nextAction += actions.length; + } else { + // backwards + var actions = getActionsToJumpBackwards(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeReverse(selector); + } + nextAction -= actions.length; + } + } + }; + + var resetPresentation = function() { + window.clearTimeout(playTimer); + + currentAction = 0; + nextAction = 0; + nbActionsRunning = 0; + + /* + * At the beginning, the visible image is the first one of the presentation + */ + $(selector + " .object-list").children().hide(); + + $(selector + " ." + json.metaData.initialBackgroundId).show(); + + $(selector + " .mouse-cursor").css({ + 'top': (json.metaData.initialMouseY * json.metaData.imageHeight) + "px", + 'left': (json.metaData.initialMouseX * json.metaData.imageWidth) + "px" + }); + + $(selector + " .mouse-cursor").show(); + } + + var startPresentationMaybe = function() { + if (autoStart) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoStart); + } + } + + /* Public API */ + + this.loadUrl = function(url) { + var dataJson; + $.ajax({ + 'async': false, + 'global': false, + 'url': url, + 'dataType': "json", + 'success': function(data) { + dataJson = data; + } + }); + + load(dataJson); + }; + + this.load = function(dataJson) { + /* Transforms data JSON to executable functions for actions */ + var execModel = dahuapp.createScreencastExecutableModel(); + execModel.loadJson(dataJson); + json = execModel.getJson(); + }; + + this.start = function() { + + /* + * Subscription of methods to their events. + */ + events.onNext.subscribe(onNextEventHandler); + events.onPrevious.subscribe(onPreviousEventHandler); + events.onActionOver.subscribe(onActionOverEventHandler); + events.onActionStart.subscribe(onActionStartEventHandler); + + resetPresentation(); + + /* + * If an anchor has been specified, we place the presentation + * in the right position. + */ + jumpToAnchor(window.location.hash.substring(1)); + + /* + * If the anchor changes during the presentation, then the + * presentation is updated + */ + if ("onhashchange" in window) { + // event supported + window.onhashchange = function () { + jumpToAnchor(window.location.hash.substring(1)); + }; + } else { + // event not supported : periodical check + window.setInterval(function () { + if (window.location.hash.substring(1) !== previousAnchor) { + previousAnchor = window.location.hash.substring(1); + jumpToAnchor(window.location.hash.substring(1)); + } + }, 100); + } + + /* + * A click on the "next" button publishes a nextSlide event + */ + $(selector + " .next").click(function() { + events.onNext.publish(); + }); + + /* + * A click on the "previous" button publishes a previousSlide event + */ + $(selector + " .previous").click(function() { + events.onPrevious.publish(); + }); + + /* + * Everything is ready, show the presentation + * (hidden with style="display: none" from HTML). + */ + $("#loading").hide(); + $(selector + " .object-list").show(); + startPresentationMaybe(); + }; + }; + + self.createDahuViewer = function(selector, getParams) { + return new DahuViewerModel(selector, getParams); + }; + + return self; + })(); + + dahuapp.viewer = viewer; +})(dahuapp || {}, jQuery); diff --git a/TP/TP01/P04/img/22f57dfb-d5d9-24ac-3822-44cdf750c340.png b/TP/TP01/P04/img/22f57dfb-d5d9-24ac-3822-44cdf750c340.png new file mode 100644 index 0000000000000000000000000000000000000000..3fbf26f279759f0f58d8a7338aaffbfe558f3b57 Binary files /dev/null and b/TP/TP01/P04/img/22f57dfb-d5d9-24ac-3822-44cdf750c340.png differ diff --git a/TP/TP01/P04/img/32df9339-a8f1-add7-c8f7-5bad61108d22.png b/TP/TP01/P04/img/32df9339-a8f1-add7-c8f7-5bad61108d22.png new file mode 100644 index 0000000000000000000000000000000000000000..f1266f2a39446e4260526f6b7b1c027d12ef3938 Binary files /dev/null and b/TP/TP01/P04/img/32df9339-a8f1-add7-c8f7-5bad61108d22.png differ diff --git a/TP/TP01/P04/img/34af7a1e-a62c-bf60-4b6d-1d5bba8fbab3.png b/TP/TP01/P04/img/34af7a1e-a62c-bf60-4b6d-1d5bba8fbab3.png new file mode 100644 index 0000000000000000000000000000000000000000..52482414ce6df08b6c7b071f6d3732bdd2d3c336 Binary files /dev/null and b/TP/TP01/P04/img/34af7a1e-a62c-bf60-4b6d-1d5bba8fbab3.png differ diff --git a/TP/TP01/P04/img/7df40e66-e67e-7070-6f6a-adc26e6841f6.png b/TP/TP01/P04/img/7df40e66-e67e-7070-6f6a-adc26e6841f6.png new file mode 100644 index 0000000000000000000000000000000000000000..cc84ce5ed3d0552e88f48cb291208885940fee67 Binary files /dev/null and b/TP/TP01/P04/img/7df40e66-e67e-7070-6f6a-adc26e6841f6.png differ diff --git a/TP/TP01/P04/img/8f253579-c94d-29b5-6f1e-e239b16c6a7d.png b/TP/TP01/P04/img/8f253579-c94d-29b5-6f1e-e239b16c6a7d.png new file mode 100644 index 0000000000000000000000000000000000000000..801e80a45e43a07ae6cdc01395905b3154aa22a6 Binary files /dev/null and b/TP/TP01/P04/img/8f253579-c94d-29b5-6f1e-e239b16c6a7d.png differ diff --git a/TP/TP01/P04/img/a53fecfe-4d94-0def-1a43-91162745c337.png b/TP/TP01/P04/img/a53fecfe-4d94-0def-1a43-91162745c337.png new file mode 100644 index 0000000000000000000000000000000000000000..2dc963034c7ded6db13dd59a847ddfa29da2c64b Binary files /dev/null and b/TP/TP01/P04/img/a53fecfe-4d94-0def-1a43-91162745c337.png differ diff --git a/TP/TP01/P04/img/b91ea9d5-6005-3dc0-3c68-2229b7f23e3d.png b/TP/TP01/P04/img/b91ea9d5-6005-3dc0-3c68-2229b7f23e3d.png new file mode 100644 index 0000000000000000000000000000000000000000..f1ea0c31ccf29bfb76e3d9332cc6bf9d8d8711dd Binary files /dev/null and b/TP/TP01/P04/img/b91ea9d5-6005-3dc0-3c68-2229b7f23e3d.png differ diff --git a/TP/TP01/P04/img/c92f1c4d-511d-9b6d-0af1-d38d47a82980.png b/TP/TP01/P04/img/c92f1c4d-511d-9b6d-0af1-d38d47a82980.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf03054082b13dd8116da3c9a01024adb0e53ed Binary files /dev/null and b/TP/TP01/P04/img/c92f1c4d-511d-9b6d-0af1-d38d47a82980.png differ diff --git a/TP/TP01/P04/img/cbd2a76c-7f63-2a57-a82e-ca585b89e917.png b/TP/TP01/P04/img/cbd2a76c-7f63-2a57-a82e-ca585b89e917.png new file mode 100644 index 0000000000000000000000000000000000000000..65455926d9de613f4eb0364a1a44621cc4fdc4b6 Binary files /dev/null and b/TP/TP01/P04/img/cbd2a76c-7f63-2a57-a82e-ca585b89e917.png differ diff --git a/TP/TP01/P04/img/cursor-pause.png b/TP/TP01/P04/img/cursor-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9c93cc142f4326a188eafc3c0fe96f2975dcab0c Binary files /dev/null and b/TP/TP01/P04/img/cursor-pause.png differ diff --git a/TP/TP01/P04/img/cursor.png b/TP/TP01/P04/img/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..5b4a20e63078ce18bb11a4e601a1994b261522ef Binary files /dev/null and b/TP/TP01/P04/img/cursor.png differ diff --git a/TP/TP01/P04/img/d0874d2b-ad91-6fac-ec2d-53b7588ffe67.png b/TP/TP01/P04/img/d0874d2b-ad91-6fac-ec2d-53b7588ffe67.png new file mode 100644 index 0000000000000000000000000000000000000000..2f57eff22f1e262f02db67da22a510138b7cb1b2 Binary files /dev/null and b/TP/TP01/P04/img/d0874d2b-ad91-6fac-ec2d-53b7588ffe67.png differ diff --git a/TP/TP01/P04/img/d59762c8-7b29-dc5e-1005-176ef0163664.png b/TP/TP01/P04/img/d59762c8-7b29-dc5e-1005-176ef0163664.png new file mode 100644 index 0000000000000000000000000000000000000000..b4f2db23598087e98c77d09c774c1a72ca0215ad Binary files /dev/null and b/TP/TP01/P04/img/d59762c8-7b29-dc5e-1005-176ef0163664.png differ diff --git a/TP/TP01/P04/img/ea723de1-bb7a-95c7-935a-530021dffd8e.png b/TP/TP01/P04/img/ea723de1-bb7a-95c7-935a-530021dffd8e.png new file mode 100644 index 0000000000000000000000000000000000000000..1923aa3f5fa62f4930fc827bb9cf4b61e51b580b Binary files /dev/null and b/TP/TP01/P04/img/ea723de1-bb7a-95c7-935a-530021dffd8e.png differ diff --git a/TP/TP01/P04/index.html b/TP/TP01/P04/index.html new file mode 100644 index 0000000000000000000000000000000000000000..d283446ff7baa36d57a86520586ba6c04f2a6c05 --- /dev/null +++ b/TP/TP01/P04/index.html @@ -0,0 +1,375 @@ +<!DOCTYPE html> + +<html lang="en"> + +<head> +<title>Dahu Presentation +</title> +<meta charset="utf-8"> +<script src="http://code.jquery.com/jquery-1.9.1.min.js" type="text/javascript"> +</script> +<script src="parse-search.js" type="text/javascript"> +</script> + +<link rel="stylesheet" href="dahuapp.viewer.css"><style>.s1-o2{background-color: #FFFFDD;width: 240px} +.s2-o2{background-color: #FFFFDD;width: 240px} +.s3-o2{background-color: #FFFFDD;width: 240px} +.s5-o2{background-color: #FFFFDD;width: 240px} +.s6-o2{background-color: #FFFFDD;width: 240px} +.s9-o2{background-color: #FFFFDD;width: 240px} +.s10-o2{background-color: #FFFFDD;width: 240px} +.s11-o2{background-color: #FFFFDD;width: 240px} +</style> +</head> + +<body> + +<div id="my-dahu-presentation"> + +<div id="loading">Loading presentation... +</div> + +<div class="object-list" style="display: none"> +<img src="img/b91ea9d5-6005-3dc0-3c68-2229b7f23e3d.png" alt="img/b91ea9d5-6005-3dc0-3c68-2229b7f23e3d.png" class="background b91ea9d5-6005-3dc0-3c68-2229b7f23e3d0"> +<img src="img/c92f1c4d-511d-9b6d-0af1-d38d47a82980.png" alt="img/c92f1c4d-511d-9b6d-0af1-d38d47a82980.png" class="background c92f1c4d-511d-9b6d-0af1-d38d47a829800"> + +<div class="tooltip s1-o2">Supprimer le bloc Derivator. +</div> +<img src="img/32df9339-a8f1-add7-c8f7-5bad61108d22.png" alt="img/32df9339-a8f1-add7-c8f7-5bad61108d22.png" class="background 32df9339-a8f1-add7-c8f7-5bad61108d220"> + +<div class="tooltip s2-o2">Supprimer les signaux qui ne sont plus connectés. +</div> +<img src="img/22f57dfb-d5d9-24ac-3822-44cdf750c340.png" alt="img/22f57dfb-d5d9-24ac-3822-44cdf750c340.png" class="background 22f57dfb-d5d9-24ac-3822-44cdf750c3400"> + +<div class="tooltip s3-o2">Supprimer les signaux qui ne sont plus connectés. +</div> +<img src="img/d59762c8-7b29-dc5e-1005-176ef0163664.png" alt="img/d59762c8-7b29-dc5e-1005-176ef0163664.png" class="background d59762c8-7b29-dc5e-1005-176ef01636640"> +<img src="img/ea723de1-bb7a-95c7-935a-530021dffd8e.png" alt="img/ea723de1-bb7a-95c7-935a-530021dffd8e.png" class="background ea723de1-bb7a-95c7-935a-530021dffd8e0"> + +<div class="tooltip s5-o2">Sélectionner les paramètres de l'oscilloscope. +</div> +<img src="img/7df40e66-e67e-7070-6f6a-adc26e6841f6.png" alt="img/7df40e66-e67e-7070-6f6a-adc26e6841f6.png" class="background 7df40e66-e67e-7070-6f6a-adc26e6841f60"> + +<div class="tooltip s6-o2">Réduire le nombre d'entrées à 2. +</div> +<img src="img/d0874d2b-ad91-6fac-ec2d-53b7588ffe67.png" alt="img/d0874d2b-ad91-6fac-ec2d-53b7588ffe67.png" class="background d0874d2b-ad91-6fac-ec2d-53b7588ffe670"> +<img src="img/34af7a1e-a62c-bf60-4b6d-1d5bba8fbab3.png" alt="img/34af7a1e-a62c-bf60-4b6d-1d5bba8fbab3.png" class="background 34af7a1e-a62c-bf60-4b6d-1d5bba8fbab30"> +<img src="img/cbd2a76c-7f63-2a57-a82e-ca585b89e917.png" alt="img/cbd2a76c-7f63-2a57-a82e-ca585b89e917.png" class="background cbd2a76c-7f63-2a57-a82e-ca585b89e9170"> + +<div class="tooltip s9-o2">Ouvrir les paramètres du bloc Integrator. Choisir la valeur initiale de l'intégrale (-1 dans ce cas). +</div> +<img src="img/a53fecfe-4d94-0def-1a43-91162745c337.png" alt="img/a53fecfe-4d94-0def-1a43-91162745c337.png" class="background a53fecfe-4d94-0def-1a43-91162745c3370"> + +<div class="tooltip s10-o2">Démarrer la simulation. +</div> +<img src="img/8f253579-c94d-29b5-6f1e-e239b16c6a7d.png" alt="img/8f253579-c94d-29b5-6f1e-e239b16c6a7d.png" class="background 8f253579-c94d-29b5-6f1e-e239b16c6a7d0"> + +<div class="tooltip s11-o2">Mettre à l'échelle l'écran de l'oscilloscope. Oberver le résultat obtenu pour l'intégration de la fonction sinusoïde. +</div> + +<div class="mouse-cursor"> +<img src="img/cursor.png" alt="img/cursor.png" class="mouse-cursor-normal"> +<img src="img/cursor-pause.png" alt="img/cursor-pause.png" style="display: none" class="mouse-cursor-pause"> +</div> +</div> + +<div class="control" style="top: 616px;"> +<button class="previous">Previous +</button> +<button class="next">Next +</button> +</div> +</div> +<script src="dahuapp.js" type="text/javascript"> +</script> +<script src="dahuapp.viewer.js" type="text/javascript"> +</script> +<script type="text/javascript">(function($) { + var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams); + myPresentation.load({ + "metaData": { + "imageWidth": 800, + "imageHeight": 600, + "initialBackgroundId": "b91ea9d5-6005-3dc0-3c68-2229b7f23e3d0", + "initialMouseX": 0.2520833333333333, + "initialMouseY": 0.3522222222222222 + }, + "action": [ + { + "id": "3", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2923611111111111, + "finalOrd": 0.47444444444444445, + "speed": 0.8 + }, + { + "id": "4", + "type": "appear", + "target": "c92f1c4d-511d-9b6d-0af1-d38d47a829800", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "26", + "type": "appear", + "target": "s1-o2", + "trigger": "afterPrevious", + "abs": 0.41, + "ord": 0.1725, + "duration": 400 + }, + { + "id": "5", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.29375, + "finalOrd": 0.4288888888888889, + "speed": 0.8 + }, + { + "id": "6", + "type": "appear", + "target": "32df9339-a8f1-add7-c8f7-5bad61108d220", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "27", + "type": "appear", + "target": "s2-o2", + "trigger": "afterPrevious", + "abs": 0.43, + "ord": 0.15125, + "duration": 400 + }, + { + "id": "7", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2638888888888889, + "finalOrd": 0.43666666666666665, + "speed": 0.8 + }, + { + "id": "8", + "type": "appear", + "target": "22f57dfb-d5d9-24ac-3822-44cdf750c3400", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "28", + "type": "appear", + "target": "s3-o2", + "trigger": "afterPrevious", + "abs": 0.3933333333333333, + "ord": 0.155, + "duration": 400 + }, + { + "id": "9", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2520833333333333, + "finalOrd": 0.45222222222222225, + "speed": 0.8 + }, + { + "id": "10", + "type": "appear", + "target": "d59762c8-7b29-dc5e-1005-176ef01636640", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "11", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.06388888888888888, + "finalOrd": 0.6655555555555556, + "speed": 0.8 + }, + { + "id": "12", + "type": "appear", + "target": "ea723de1-bb7a-95c7-935a-530021dffd8e0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "29", + "type": "appear", + "target": "s5-o2", + "trigger": "afterPrevious", + "abs": 0.22166666666666668, + "ord": 0.29375, + "duration": 400 + }, + { + "id": "13", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.09722222222222222, + "finalOrd": 0.7555555555555555, + "speed": 0.8 + }, + { + "id": "14", + "type": "appear", + "target": "7df40e66-e67e-7070-6f6a-adc26e6841f60", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "30", + "type": "appear", + "target": "s6-o2", + "trigger": "afterPrevious", + "abs": 0.15333333333333332, + "ord": 0.30875, + "duration": 400 + }, + { + "id": "15", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2659722222222222, + "finalOrd": 0.31777777777777777, + "speed": 0.8 + }, + { + "id": "16", + "type": "appear", + "target": "d0874d2b-ad91-6fac-ec2d-53b7588ffe670", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "17", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.24930555555555556, + "finalOrd": 0.45222222222222225, + "speed": 0.8 + }, + { + "id": "18", + "type": "appear", + "target": "34af7a1e-a62c-bf60-4b6d-1d5bba8fbab30", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "19", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.35347222222222224, + "finalOrd": 0.3466666666666667, + "speed": 0.8 + }, + { + "id": "20", + "type": "appear", + "target": "cbd2a76c-7f63-2a57-a82e-ca585b89e9170", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "31", + "type": "appear", + "target": "s9-o2", + "trigger": "afterPrevious", + "abs": 0.35833333333333334, + "ord": 0.16125, + "duration": 400 + }, + { + "id": "21", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.28888888888888886, + "finalOrd": 0.10111111111111111, + "speed": 0.8 + }, + { + "id": "22", + "type": "appear", + "target": "a53fecfe-4d94-0def-1a43-91162745c3370", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "32", + "type": "appear", + "target": "s10-o2", + "trigger": "afterPrevious", + "abs": 0.30333333333333334, + "ord": 0.05875, + "duration": 400 + }, + { + "id": "23", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.1486111111111111, + "finalOrd": 0.6633333333333333, + "speed": 0.8 + }, + { + "id": "24", + "type": "appear", + "target": "8f253579-c94d-29b5-6f1e-e239b16c6a7d0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "33", + "type": "appear", + "target": "s11-o2", + "trigger": "afterPrevious", + "abs": 0.21166666666666667, + "ord": 0.295, + "duration": 400 + } + ] +}); + myPresentation.start(); +})(jQuery); + +</script> +</body> +</html> \ No newline at end of file diff --git a/TP/TP01/P04/parse-search.js b/TP/TP01/P04/parse-search.js new file mode 100644 index 0000000000000000000000000000000000000000..e7d01c07f6a5d45b9fcabd5d271a8c6cfc5f00e2 --- /dev/null +++ b/TP/TP01/P04/parse-search.js @@ -0,0 +1,14 @@ +// Adapted from http://stackoverflow.com/questions/3234125/creating-array-from-window-location-hash +(function () { + var search = window.location.search.slice(1); + var array = search.split("&"); + + var values, form_data = {}; + + for (var i = 0; i < array.length; i += 1) { + values = array[i].split("="); + form_data[values[0]] = unescape(values[1]); + } + window.getParams = form_data; +}()) + diff --git a/TP/TP01/P05/dahuapp.js b/TP/TP01/P05/dahuapp.js new file mode 100644 index 0000000000000000000000000000000000000000..41c69e9169345a9a6703325d5557a4cc36913e19 --- /dev/null +++ b/TP/TP01/P05/dahuapp.js @@ -0,0 +1,880 @@ +"use strict"; + +/** + * Dahuapp core module. + * + * @param window window javascript object. + * @param $ jQuery + * @returns dahuapp core module. + */ +(function (window, $) { + var dahuapp = (function () { + + var self = {}; + + /* private API */ + + var DahuScreencastGenerator = function () { + + /* + * Format the specified string in a readable format. + */ + function htmlFormat(htmlString) { + var i; + var readableHTML = htmlString; + var lb = '\n'; + var htags = ["<html", "</html>", "</head>", "<title", "</title>", "<meta", "<link", "</body>"]; + for (i = 0; i < htags.length; ++i) { + var hhh = htags[i]; + readableHTML = readableHTML.replace(new RegExp(hhh, 'gi'), lb + hhh); + } + var btags = ["</div>", "</section>", "</span>", "<br>", "<br />", "<blockquote", "</blockquote>", "<ul", "</ul>", "<ol", "</ol>", "<li", "<\!--", "<script", "</script>"]; + for (i = 0; i < btags.length; ++i) { + var bbb = btags[i]; + readableHTML = readableHTML.replace(new RegExp(bbb, 'gi'), lb + bbb); + } + var ftags = ["<img", "<legend", "</legend>", "<button", "</button>"]; + for (i = 0; i < ftags.length; ++i) { + var fff = ftags[i]; + readableHTML = readableHTML.replace(new RegExp(fff, 'gi'), lb + fff); + } + var xtags = ["<body", "<head", "<div", "<section", "<span", "<p"]; + for (i = 0; i < xtags.length; ++i) { + var xxx = xtags[i]; + readableHTML = readableHTML.replace(new RegExp(xxx, 'gi'), lb + lb + xxx); + } + return readableHTML; + } + + /* + * Generates the html header. + */ + var generateHtmlHeader = function ($generated, cssGen) { + $('head', $generated) + .append($(document.createElement('title')) + .append("Dahu Presentation"))/* TODO: make this customizable */ + .append($(document.createElement('meta')) + .attr({'charset': 'utf-8'})) + .append($(document.createElement('script')) + .attr({'src': 'http://code.jquery.com/jquery-1.9.1.min.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'parse-search.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('link')) + .attr({'rel': 'stylesheet', 'href': 'dahuapp.viewer.css'})) + .append($(document.createElement('style')) + .append(cssGen)); + }; + + /* + * Generates the objects. + */ + + var generateHtmlBackgroundImage = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('img')) + .attr({'src': object.img, 'alt': object.img, 'class': 'background ' + object.id})); + }; + var generateHtmlTooltip = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'tooltip ' + object.id}) + .append(object.text)); + }; + + var generateCssTooltip = function ($generated, object) { + var style = []; + + if( object.color != null ) { + style.push('background-color: ' + object.color); + } + if( object.width != null ) { + style.push('width: ' + object.width); + } + + if( style.length != 0 ) { + $generated.append( + '.' + object.id + '{' + style.join(';') + '}\n'); + } + + return $generated; + }; + + /* + * Returns the code used to call the viewer to the presentation. + */ + var getBasicCallCode = function (jsonModel) { + var code = '(function($) {\n'; + code += ' var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams);\n'; + code += ' myPresentation.load(' + jsonModel + ');\n'; + code += ' myPresentation.start();\n'; + code += '})(jQuery);\n'; + return code; + }; + + /* + * Generates the html body. + */ + var generateHtmlBody = function ($generated, jsonModel, jsonGen) { + $('body', $generated) + /* We could use a <section> here too, but it does not work with MS IE 8. + Alternatively, adding this in the header would work: + + <!--[if lt IE 9]> + <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + */ + .append($(document.createElement('div')) + .attr({'id': 'my-dahu-presentation'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.viewer.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'type': 'text/javascript'}) + .append(getBasicCallCode(jsonGen))); + $('#my-dahu-presentation', $generated) + .append($(document.createElement('div')) + .attr({'id': 'loading'}).append("Loading presentation...")) + .append($(document.createElement('div')) + .attr({'class': 'object-list', + 'style': 'display: none'})) + .append($(document.createElement('div')) + .attr({'class': 'control'})); + + /* Adding the objects to the page */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "background": + generateHtmlBackgroundImage($generated, object); + break; + case "tooltip": + generateHtmlTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + /* Warning here, i'm not sure if $.each is always over, here */ + + /* Adding the control buttons to the page */ + $('.control', $generated) + .css({'top': (jsonModel.getImageHeight() + 16) + 'px'}) + .append($(document.createElement('button')) + .attr({'class': 'previous'}) + .append('Previous')) + .append($(document.createElement('button')) + .attr({'class': 'next'}) + .append('Next')); + + /* Adding the mouse cursor image */ + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'mouse-cursor'}) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor.png', 'alt': 'img/cursor.png', 'class': 'mouse-cursor-normal'})) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor-pause.png', 'alt': 'img/cursor-pause.png', + 'style': 'display: none', 'class': 'mouse-cursor-pause'}))); + }; + + /* + * Generates the css String with the Json model. + */ + this.generateCssString = function (jsonModel) { + var $generated = $('<style></style>'); + + /* Going through each object */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "tooltip": + generateCssTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + return $generated.text(); + } + + /* + * Generates the html String with the Json model. + */ + this.generateHtmlString = function (jsonModel, jsonGen, cssGen) { + /* Initialising the compilation area */ + var $generated = $(document.createElement('div')); + + /* We create the html using the json */ + $generated.append($(document.createElement('html')) + .attr({'lang': 'en'})); + $('html', $generated) + .append($(document.createElement('head'))) + .append($(document.createElement('body'))); + + generateHtmlHeader($generated, cssGen); + generateHtmlBody($generated, jsonModel, jsonGen); + + var result = htmlFormat($generated.html()); + + return '<!DOCTYPE html>\n' + result; + }; + + /* + * Generates the generated JSON using the JSONmodel. + * @param {object} jsonModel The json model to transform. + * @param {java.awt.Dimension} imgDim The dimension of images. + */ + this.generateJsonString = function (jsonModel, imgDim) { + var generated = self.createScreencastGeneratedModel(); + generated.setImageSize(imgDim.width, imgDim.height); + generated.setInitialBackground(jsonModel.getInitialBackground()); + generated.setInitialMousePos(jsonModel.getInitialMousePos()); + for (var i = 0; i < jsonModel.getNbSlide(); i++) { + var actionList = jsonModel.getActionList(i); + for (var j = 0; j < actionList.length; j++) { + /* + * We don't add the two first actions of the first slide + * because they are present in the presentation metadata. + * It corresponds to the mouse initial pos and first background. + */ + if (i > 0 || j > 1) { + generated.addAction(actionList[j], imgDim.width, imgDim.height); + } + } + } + return generated.getJson(); + }; + }; + + /* + * Model for a JSON object that will only be used by the viewer, never + * saved on a file, used to transform the properties of actions + * specified on the JSON file of a presentation to executable + * functions for each action. + */ + var DahuScreencastExecutableModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* + * Creates a functions representing the specified action, and adds + * it to this object. + * @param {object} action + */ + var addExecutableAction = function (action) { + var executableAction = { + 'id': action.id, + 'trigger': action.trigger, + 'target': action.target, + 'delayAfter': action.delayAfter, + 'doneFunction': function (events, selector) { + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.delayAfter); + } + }; + if (executableAction.delayAfter == null) { + executableAction.delayAfter = 200; + } + switch (action.type.toLowerCase()) { + case "appear": + executableAction.abs = (action.abs * json.metaData.imageWidth) + 'px'; + executableAction.ord = (action.ord * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(); + }; + break; + case "disappear": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + $(selector + ' .' + this.target).hide(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).show(); + }; + executableAction.executeImmediately = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + break; + case "move": + executableAction.finalAbs = (action.finalAbs * json.metaData.imageWidth) + 'px'; + executableAction.finalOrd = (action.finalOrd * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.speed = action.speed; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + if (this.duration == null) { + var initialAbsPix = this.initialAbs.replace('px', ''); + var initialOrdPix = this.initialOrd.replace('px', ''); + var finalAbsPix = this.finalAbs.replace('px', ''); + var finalOrdPix = this.finalOrd.replace('px', ''); + var distance = Math.sqrt(Math.pow(finalAbsPix - initialAbsPix, 2) + + Math.pow(finalOrdPix - initialOrdPix, 2)); + if (!this.speed) { + this.speed = .8; // in pixel per milisecond: fast, but not too much. + } + this.duration = distance + this.speed; + if (this.duration < 200) { // Slow down a bit for short distances. + this.duration = 200; + } + } + $(sel).animate({ + 'left': this.finalAbs, + 'top': this.finalOrd + }, this.duration, 'linear', function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).css({ + 'left': this.initialAbs, + 'top': this.initialOrd + }); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + $(sel).css({ + 'left': this.finalAbs, + 'top': this.finalOrd + }); + }; + break; + case "delay": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.duration); + }; + executableAction.executeReverse = function (selector) { + // Nothing! + }; + executableAction.executeImmediately = function (selector) { + // Nothing too! + }; + break; + } + json.action.push(executableAction); + }; + + /* Public API */ + + /* + * Loads the specified JSON read from a 'presentation.json' file, + * and stores the functions representing each actions in an object. + * @param {object} jsonToLoad + */ + this.loadJson = function (jsonToLoad) { + json.metaData = jsonToLoad.metaData; + for (var i = 0; i < jsonToLoad.action.length; i++) { + addExecutableAction(jsonToLoad.action[i]); + } + }; + + /* + * Returns the object containing the functions. + */ + this.getJson = function () { + return json; + }; + }; + + /* + * Used to transform the 'dahu' file to a JSON file used by the viewer, + * which only contains some metaData and a list of actions. + */ + var DahuScreencastGeneratedModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* Public API */ + + /* + * Returns a string representation of this json. + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * Setters for the generated json metadata. + */ + this.setImageSize = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + this.setInitialMousePos = function (pos) { + json.metaData.initialMouseX = pos.x; + json.metaData.initialMouseY = pos.y; + }; + + this.setInitialBackground = function (id) { + json.metaData.initialBackgroundId = id; + }; + + this.addAction = function (action) { + json.action.push(action); + }; + + /* + * Transforms a JSON containing action properties to a JSON containing + * the execution functions. + * @param {Object} json + * @returns {Object} A json object containing the execution functions + * for all the actions of the presentation. + */ + this.toExecutableList = function (json) { + var executableList = { + metaData: json.metaData, + action: new Array() + }; + for (var i = 0; i < json.action.length; i++) { + addExecutableAction(executableList, json.action[i]); + } + return executableList; + }; + }; + + /* + * Represents a 'dahu' file for a project. + */ + var DahuScreencastModel = function () { + + /* Private API */ + + var json = {}; + + /* + * Generates a unique action ID. + * + * With this implementation, this ID is unique as long as the user + * doesn't replace it manually with a not kind value or replace + * the nextUniqueId with bad intentions. + * But maybe that a UUID is a bit tiresome to put as an anchor... + */ + var generateUniqueActionId = function () { + json.metaData.nextUniqueId++; + return json.metaData.nextUniqueId.toString(); + }; + + /* + * This method checks if the json representing a dahu project is + * in the good version. It's in case a project file was created + * with a previous version of Dahu, and that some fields are + * missing. + * + * It doesn't control each field (at the moment) but only the + * fields that can be missing due to a new Dahu version and not + * to a manual editing. + * + * This method doesn't check any Json syntax or something like that. + */ + var upgradeJsonVersion = function () { + // Checks if unique IDs are in the project file + if (!json.metaData.nextUniqueId) { + var currentId = 0; + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].action.length; j++) { + json.data[i].action[j].id = currentId.toString(); + currentId++; + } + } + json.metaData.nextUniqueId = currentId; + } + }; + + /* Public API */ + + /* + * json variable generated from a JSON file. + * @param String stringJson String loaded from JSON file. + */ + this.loadJson = function (stringJson) { + json = JSON.parse(stringJson); + upgradeJsonVersion(); + }; + + /* + * Create a new presentation variable in the JSON file which will contain slides. + */ + this.createPresentation = function (width, height) { + json.metaData = {}; + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + json.metaData.nextUniqueId = 0; + json.data = new Array(); + }; + + /* + * Add a new slide in the presentation variable of the JSON file. + * @param int index wanted for the slide. + * @param String idSlide Unique identifier for the slide. + * @param String img Related to pathname of the image. + * @param double mouseX Abscissa mouse position in %. + * @param double mouseY Ordinate mouse position in %. + * @return Index of the newly added slide. + */ + this.addSlide = function (indexSlide, idSlide, img, mouseX, mouseY, speed) { + var slide = { + "object": new Array(), + "action": new Array() + }; + json.data.splice(indexSlide, 0, slide); + this.addObject(indexSlide, "background", idSlide, img); + this.addObject(indexSlide, "mouse"); + this.addAction(indexSlide, "move", json.data[indexSlide].object[1].id, "onClick", mouseX, mouseY, speed); + this.addAction(indexSlide, "appear", json.data[indexSlide].object[0].id, "afterPrevious"); + }; + + /* + * Object factory. + * Add a new Object in the slide idSlide. + * @param int idSlide + * @param string type + * Other params can be specified depending on the object's type. + */ + this.addObject = function (idSlide, type) { + var object = { + "type": type + }; + switch (type.toLowerCase()) { + case "background": + object.id = arguments[2] + json.data[idSlide].object.length; + object.img = arguments[3] || ""; + break; + case "mouse": + object.id = "mouse-cursor"; + break; + case "tooltip": + /* + * TODO: we'll need a more robust unique name + * when we start actually using this. + */ + object.id = "s" + idSlide + "-o" + json.data[idSlide].object.length; + object.text = arguments[2] || ""; + object.color = arguments[3] || null; + object.width = arguments[4] || ""; + json.data[idSlide].object.push(object); + var objectLength = json.data[idSlide].object.length; + var last = json.data[idSlide].object[objectLength-1]; + json.data[idSlide].object[objectLength-1] = + json.data[idSlide].object[objectLength-2]; + json.data[idSlide].object[objectLength-2] = last; + break; + } + if(type.toLowerCase() != "tooltip"){ + json.data[idSlide].object.push(object); + } + }; + + /* + * Action factory. + * Add a new Action in the slide idSlide whose target is the id of an object. + * Three types of trigger : "withPrevious", "afterPrevious", "onClick". + * @param int idSlide + * @param string type + * @param string target + * @param string trigger + * Other params can be specified depending on the object's type. + */ + this.addAction = function (idSlide, type, target, trigger) { + var action = { + "id": generateUniqueActionId(), + "type": type, + "target": target, + "trigger": trigger + }; + switch (type.toLowerCase()) { + case "appear": + action.abs = arguments[4] || 0.0; + action.ord = arguments[5] || 0.0; + action.duration = arguments[6] || 0; + break; + case "disappear": + action.duration = arguments[4] || 0; + break; + case "move": + action.finalAbs = arguments[4] || 0.0; + action.finalOrd = arguments[5] || 0.0; + action.speed = arguments[6] || 0; + break; + } + json.data[idSlide].action.push(action); + }; + + this.editMouse = function (idSlide, idAction, mouseX, mouseY) { + json.data[idSlide].action[idAction].finalAbs = mouseX; + json.data[idSlide].action[idAction].finalOrd = mouseY; + }; + + /* + * Sets a title for the presentation. + * @param String title Title to set. + */ + this.setTitle = function (title) { + json.metaData.title = title; + }; + + /* + * Sets an annotation for the presentation. + * @param String annotation Annotation to set. + */ + this.setAnnotation = function (annotation) { + json.metaData.annotation = annotation; + }; + + /* + * Inverts the two slides (their positions on the table). + * @param int idSlide1 Index of the first slide. + * @param int idSlide2 Index of the second slide. + */ + this.invertSlides = function (idSlide1, idSlide2) { + var tmp = json.data[idSlide1]; + json.data[idSlide1] = json.data[idSlide2]; + json.data[idSlide2] = tmp; + }; + + /* + * Inverts the two actions (their positions on the table). + * @param int idSlide + * @param int idAction1 + * @param int idAction2 + */ + this.invertActions = function (idSlide, idAction1, idAction2) { + var tmp = json.data[idSlide].action[idAction1]; + json.data[idSlide].action[idAction1] = json.data[idSlide].action[idAction2]; + json.data[idSlide].action[idAction2] = tmp; + }; + + /* + * Returns the actions on the specified slide. + * @returns {Array} + */ + this.getActionList = function (idSlide) { + return json.data[idSlide].action; + }; + + /* + * Catches all the objects of the presentation + * @returns {Array} List of objects of the presentation + */ + this.getObjectList = function () { + var objectList = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + var indexObject = 0; + while (json.data[indexSlide].object[indexObject]) { + objectList.push(json.data[indexSlide].object[indexObject]); + indexObject++; + } + indexSlide++; + } + return objectList; + }; + + /* + * Returns an array containing all the background images. + * @returns {Array} List of background images. + */ + this.getImageList = function () { + var list = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + list.push(json.data[indexSlide].object[0].img); + indexSlide++; + } + ; + return list; + }; + + /* + * Returns an object containing the id of the first background. + * @returns {string} Id of the first background. + */ + this.getInitialBackground = function () { + return json.data[0].object[0].id; + }; + + /* + * Returns an object containing the initial mouse position. + * @returns {object} Initial position of mouse. + */ + this.getInitialMousePos = function () { + var pos = {}; + pos.x = json.data[0].action[0].finalAbs; + pos.y = json.data[0].action[0].finalOrd; + return pos; + }; + + /* + * Removes the slide at the specified index. + * @param {int} idSlide + */ + this.removeSlide = function (idSlide) { + json.data.splice(idSlide, 1); + }; + + /* + * Removes the action at the specified slide. + * @param {int} idSlide + * @param {int} idAction + */ + this.removeAction = function (idSlide, idAction) { + json.data[idSlide].action.splice(idAction, 1); + }; + + /* + * Removes the specified object from the slide. + * Also removes all the actions attached to this object. + * @param {int} idSlide + * @param {int} idObject + */ + this.removeObject = function (idSlide, idObject) { + var removed = json.data[idSlide].object.splice(idObject, 1); + for (var i = 0; i < json.data.length; i++) { + var j = 0; + while (json.data[i].action[j]) { + if (json.data[i].action[j].target === removed.id) { + json.data[i].action.splice(j, 1); + } else { + j++; + } + } + } + }; + + /* + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * @returns {String} returns the index for the next slide. + */ + this.getNbSlide = function () { + return json.data.length; + }; + + /* + * @return {object} returns the object identified by idSlide + */ + this.getSlide = function (idSlide) { + return json.data[idSlide]; + }; + + /* + * Sets the size of images for the generated presentation. + * The parameters can be null : it means there are no + * requirement for this dimension. + * @param {int} width New width for the generated images. + * @param {int} height New height for the generated images. + */ + this.setImageSizeRequirements = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + /* + * Gets the width of images for the generated presentation. + * @return {int or null} Width of generated images. + */ + this.getImageWidth = function () { + return json.metaData.imageWidth; + }; + + /* + * Gets the height of images for the generated presentation. + * @return {int or null} Height of generated images. + */ + this.getImageHeight = function () { + return json.metaData.imageHeight; + }; + + /* + * Gets a background image (no one in particular, the first met). + * @return {string} The name of a background image. + */ + this.getABackgroundImage = function () { + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].object.length; j++) { + if (json.data[i].object[j].type === "background") { + return json.data[i].object[j].img; + } + } + } + return null; + }; + }; + + /* public API */ + + self.version = "0.0.1"; + + self.createScreencastGenerator = function createScreencastGenerator() { + return new DahuScreencastGenerator(); + }; + + self.createScreencastModel = function createScreencastModel() { + return new DahuScreencastModel(); + }; + + self.createScreencastExecutableModel = function createScreencastExecutableModel() { + return new DahuScreencastExecutableModel(); + }; + + self.createScreencastGeneratedModel = function createScreencastGeneratedModel() { + return new DahuScreencastGeneratedModel(); + }; + + return self; + })(); + + window.dahuapp = dahuapp; + +})(window, jQuery); \ No newline at end of file diff --git a/TP/TP01/P05/dahuapp.viewer.css b/TP/TP01/P05/dahuapp.viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ea934576dad6ca9263a6163de58f5fe4534d1f0b --- /dev/null +++ b/TP/TP01/P05/dahuapp.viewer.css @@ -0,0 +1,25 @@ +.object-list { + position: absolute; + margin: 0px; + padding: 0px; +} + +.mouse-cursor { + position: absolute; +} + +.control { + position: relative; +} + +.background { + position: absolute; +} + +.tooltip { + position: absolute; + width: 100px; + padding: 4px; + margin: 2px; + border: 2px black solid; +} \ No newline at end of file diff --git a/TP/TP01/P05/dahuapp.viewer.js b/TP/TP01/P05/dahuapp.viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..12ad03b2cdc503a8fd6ff3f5fdc2a74edbb36edb --- /dev/null +++ b/TP/TP01/P05/dahuapp.viewer.js @@ -0,0 +1,456 @@ +"use strict"; + +/** + * Dahuapp viewer module. + * + * @param dahuapp dahuapp object to augment with module. + * @param $ jQuery + * @returns dahuapp extended with viewer module. + */ + +(function(dahuapp, $) { + var viewer = (function() { + + var self = {}; + + var DahuViewerModel = function(select, getParams) { + + /* Private API */ + + var json = null; + var selector = select; + var parseAutoOption = function(name, defaultValue) { + var res = getParams[name]; + if (res == null) { + if (name == 'auto') { + return false; + } else { + return parseAutoOption('auto', defaultValue); + } + } + if (res.toLowerCase() === 'false') { + return false; + } + res = parseInt(res); + if (isNaN(res)) { + // e.g. ?autoplay or ?autoplay=true + return defaultValue; + } + return res; + } + + /* Whether to wait for "next" event between actions */ + var autoPlay = parseAutoOption('autoplay', 5000); + /* Whether to wait for "next" event on page load */ + var autoStart = parseAutoOption('autostart', 5000); + /* Whether to loop back to start at the end of presentation */ + var autoLoop = parseAutoOption('autoloop', 5000); + + var events = (function() { + var self = {}; + /* + * Creates a generic event. + */ + var createEvent = function() { + var callbacks = $.Callbacks(); + return { + publish: callbacks.fire, + subscribe: callbacks.add, + unsubscribe: callbacks.remove, + unsubscribeAll: callbacks.empty + }; + }; + /* + * Called when the button next is pressed. + */ + self.onNext = createEvent(); + /* + * Called when the button previous is pressed. + */ + self.onPrevious = createEvent(); + /* + * Called when an action is over. + */ + self.onActionOver = createEvent(); + /* + * Called when an action starts. + */ + self.onActionStart = createEvent(); + /* + * Called when at least one action was running and has finished. + */ + self.onAllActionFinish = createEvent(); + + return self; + })(); + + /* + * Variables used like index for methodes subscribed. + */ + var currentAction = 0; /* Action currently running */ + var nextAction = 0; /* Action to execute on 'Next' click */ + var nbActionsRunning = 0; + var previousAnchor = -1; /* Last entered anchor, only used in + * case the 'onhashchange' event is + * not supported by the web browser */ + + /* + * Functions to reinitialise running actions and subscribed + * callbacks (reinitialise is called once without stopping + * all the actions, so the two functions are separated). + */ + var stopAllActions = function() { + $(selector + " .object-list").children().stop(true, true); + reinitialiseCallbackLists(); + nbActionsRunning = 0; + }; + var reinitialiseCallbackLists = function() { + events.onActionStart.unsubscribeAll(); + events.onActionStart.subscribe(onActionStartEventHandler); + events.onAllActionFinish.unsubscribeAll(); + }; + + /* + * Timer used to program onNext event in autoplay mode. + */ + var playTimer = 0; + + /* + * Function used when an "onNextEvent" event is caught. + */ + var onNextEventHandler = function() { + /* + * If the user pressed "next" before an autoplay event + * is triggered, it replaces the autoplay event, hence + * cancels it: + */ + window.clearTimeout(playTimer); + + enterAnimationMode(); + stopAllActions(); + var tmpAction = nextAction; + var onlyWithPrevious = true; + nextAction++; + currentAction = nextAction; + while (json.action[currentAction] && onlyWithPrevious) { + switch (json.action[currentAction].trigger) { + case 'onClick': + nextAction = currentAction; + onlyWithPrevious = false; + break; + case 'withPrevious': + var tmp = currentAction; + /* + * We can't directly pass 'execute' as callback because we + * allow the 'execute' function to reference a property of the + * object (by using 'this.property') so we have to call the + * function in the containing object to make that available + */ + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + while (json.action[nextAction] && json.action[nextAction].trigger !== 'onClick') { + nextAction++; + } + onlyWithPrevious = false; + break; + } + currentAction++; + } + if (json.action[tmpAction]) { + launch(json.action[tmpAction]); + } + if (nextAction > json.action.length) { + nextAction = json.action.length; + } + }; + + /* + * Function used when an "onPreviousEvent" event is caught. + */ + var onPreviousEventHandler = function() { + stopAllActions(); + currentAction = nextAction - 1; + while (json.action[currentAction] && json.action[currentAction].trigger !== 'onClick') { + launchReverse(json.action[currentAction]); + currentAction--; + } + /* currentAction = -1 means that it's the beginning */ + if (currentAction > -1) { + launchReverse(json.action[currentAction]); + } + if (currentAction < 0) { + currentAction = 0; + } + nextAction = currentAction; + }; + + /* + * Function used when an "onActionOverEvent" event is caught. + */ + var onActionOverEventHandler = function() { + nbActionsRunning--; + if (nbActionsRunning === 0) { + events.onAllActionFinish.publish(events, selector); + reinitialiseCallbackLists(); + while (json.action[currentAction]) { + switch (json.action[currentAction].trigger) { + case 'onClick': + leaveAnimationMode(); + if (autoPlay && nbActionsRunning === 0) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoPlay); + } + return; + case 'withPrevious': + var tmp = currentAction; + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + currentAction++; + return; + } + currentAction++; + + } + if (autoLoop && nbActionsRunning === 0) { + setTimeout(function () { + resetPresentation(); + startPresentationMaybe(); + }, autoLoop); + } + } + leaveAnimationMode(); + }; + + /* + * Function used when an "onActionStartEvent" event is caught. + */ + var onActionStartEventHandler = function() { + nbActionsRunning++; + }; + + /* + * Enter and leave "animation" mode. The viewer is in + * animation mode when something is going on without human + * interaction (i.e. executing actions before the next + * "onClick"). + */ + var enterAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').hide(); + $(selector + ' .mouse-cursor-normal').show(); + }; + + var leaveAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').show(); + $(selector + ' .mouse-cursor-normal').hide(); + }; + + /* + * Function used to perform actions. + */ + var launch = function(action) { + action.execute(events, selector); + }; + var launchReverse = function(action) { + action.executeReverse(selector); + }; + + /* + * The two following methods each returns an array containing the + * actions to execute to reach the given anchor (respectively + * forward or backwards). + * + * If the given anchor matches none of the actions, then an empty + * array is returned. + */ + var getActionsToJumpForward = function(anchor) { + var actions = new Array(); + for (var i = nextAction; i < json.action.length; i++) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + if (json.action[i].id == anchor) { + return actions; + } else { + actions.push(json.action[i]); + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + var getActionsToJumpBackwards = function(anchor) { + var actions = new Array(); + for (var i = nextAction - 1; i >= 0; i--) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + actions.push(json.action[i]); + if (json.action[i].id == anchor) { + return actions; + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + + /* + * Updates the position of the presentation depending on the + * given anchor (next action wanted). + */ + var jumpToAnchor = function(anchor) { + if (anchor !== '') { + stopAllActions(); + if (anchor > nextAction) { + // forward + var actions = getActionsToJumpForward(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeImmediately(selector); + } + nextAction += actions.length; + } else { + // backwards + var actions = getActionsToJumpBackwards(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeReverse(selector); + } + nextAction -= actions.length; + } + } + }; + + var resetPresentation = function() { + window.clearTimeout(playTimer); + + currentAction = 0; + nextAction = 0; + nbActionsRunning = 0; + + /* + * At the beginning, the visible image is the first one of the presentation + */ + $(selector + " .object-list").children().hide(); + + $(selector + " ." + json.metaData.initialBackgroundId).show(); + + $(selector + " .mouse-cursor").css({ + 'top': (json.metaData.initialMouseY * json.metaData.imageHeight) + "px", + 'left': (json.metaData.initialMouseX * json.metaData.imageWidth) + "px" + }); + + $(selector + " .mouse-cursor").show(); + } + + var startPresentationMaybe = function() { + if (autoStart) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoStart); + } + } + + /* Public API */ + + this.loadUrl = function(url) { + var dataJson; + $.ajax({ + 'async': false, + 'global': false, + 'url': url, + 'dataType': "json", + 'success': function(data) { + dataJson = data; + } + }); + + load(dataJson); + }; + + this.load = function(dataJson) { + /* Transforms data JSON to executable functions for actions */ + var execModel = dahuapp.createScreencastExecutableModel(); + execModel.loadJson(dataJson); + json = execModel.getJson(); + }; + + this.start = function() { + + /* + * Subscription of methods to their events. + */ + events.onNext.subscribe(onNextEventHandler); + events.onPrevious.subscribe(onPreviousEventHandler); + events.onActionOver.subscribe(onActionOverEventHandler); + events.onActionStart.subscribe(onActionStartEventHandler); + + resetPresentation(); + + /* + * If an anchor has been specified, we place the presentation + * in the right position. + */ + jumpToAnchor(window.location.hash.substring(1)); + + /* + * If the anchor changes during the presentation, then the + * presentation is updated + */ + if ("onhashchange" in window) { + // event supported + window.onhashchange = function () { + jumpToAnchor(window.location.hash.substring(1)); + }; + } else { + // event not supported : periodical check + window.setInterval(function () { + if (window.location.hash.substring(1) !== previousAnchor) { + previousAnchor = window.location.hash.substring(1); + jumpToAnchor(window.location.hash.substring(1)); + } + }, 100); + } + + /* + * A click on the "next" button publishes a nextSlide event + */ + $(selector + " .next").click(function() { + events.onNext.publish(); + }); + + /* + * A click on the "previous" button publishes a previousSlide event + */ + $(selector + " .previous").click(function() { + events.onPrevious.publish(); + }); + + /* + * Everything is ready, show the presentation + * (hidden with style="display: none" from HTML). + */ + $("#loading").hide(); + $(selector + " .object-list").show(); + startPresentationMaybe(); + }; + }; + + self.createDahuViewer = function(selector, getParams) { + return new DahuViewerModel(selector, getParams); + }; + + return self; + })(); + + dahuapp.viewer = viewer; +})(dahuapp || {}, jQuery); diff --git a/TP/TP01/P05/img/00ac7398-6f83-2ebc-85e3-1feb000bc364.png b/TP/TP01/P05/img/00ac7398-6f83-2ebc-85e3-1feb000bc364.png new file mode 100644 index 0000000000000000000000000000000000000000..39204b52e286d85b8f26c712863e695ba2a9478d Binary files /dev/null and b/TP/TP01/P05/img/00ac7398-6f83-2ebc-85e3-1feb000bc364.png differ diff --git a/TP/TP01/P05/img/014336b3-9a2a-1817-25b9-50ff3ccbccd4.png b/TP/TP01/P05/img/014336b3-9a2a-1817-25b9-50ff3ccbccd4.png new file mode 100644 index 0000000000000000000000000000000000000000..54242b296a5638f08834280a7cf08b9808e62e76 Binary files /dev/null and b/TP/TP01/P05/img/014336b3-9a2a-1817-25b9-50ff3ccbccd4.png differ diff --git a/TP/TP01/P05/img/135e6dd3-3dee-7be0-6d6c-3407ce073d0e.png b/TP/TP01/P05/img/135e6dd3-3dee-7be0-6d6c-3407ce073d0e.png new file mode 100644 index 0000000000000000000000000000000000000000..4442249df56774a8650d0ea83986bbe12ea5831b Binary files /dev/null and b/TP/TP01/P05/img/135e6dd3-3dee-7be0-6d6c-3407ce073d0e.png differ diff --git a/TP/TP01/P05/img/40772f5f-7b7e-ea5b-18a7-dbeecc8d5774.png b/TP/TP01/P05/img/40772f5f-7b7e-ea5b-18a7-dbeecc8d5774.png new file mode 100644 index 0000000000000000000000000000000000000000..e7ce24ddce5012e77b40ef83201a327c680871d5 Binary files /dev/null and b/TP/TP01/P05/img/40772f5f-7b7e-ea5b-18a7-dbeecc8d5774.png differ diff --git a/TP/TP01/P05/img/4233bd5f-4100-b71d-e0e8-99a696a682f4.png b/TP/TP01/P05/img/4233bd5f-4100-b71d-e0e8-99a696a682f4.png new file mode 100644 index 0000000000000000000000000000000000000000..70bfa43103e7e4e24dee922458b9253e68dda50b Binary files /dev/null and b/TP/TP01/P05/img/4233bd5f-4100-b71d-e0e8-99a696a682f4.png differ diff --git a/TP/TP01/P05/img/537c2394-0d22-e637-7dc9-4dcefe8ffb78.png b/TP/TP01/P05/img/537c2394-0d22-e637-7dc9-4dcefe8ffb78.png new file mode 100644 index 0000000000000000000000000000000000000000..2d4fc5176f5e5be564cbb6aef60082e0ba359b03 Binary files /dev/null and b/TP/TP01/P05/img/537c2394-0d22-e637-7dc9-4dcefe8ffb78.png differ diff --git a/TP/TP01/P05/img/58f2a040-93d0-140f-ad3b-f16229898b92.png b/TP/TP01/P05/img/58f2a040-93d0-140f-ad3b-f16229898b92.png new file mode 100644 index 0000000000000000000000000000000000000000..33def4d21d9a127bd0c72b5c6a5b07ebaf2c8ded Binary files /dev/null and b/TP/TP01/P05/img/58f2a040-93d0-140f-ad3b-f16229898b92.png differ diff --git a/TP/TP01/P05/img/7c27ec34-4ec2-09ac-de29-aa514a30772a.png b/TP/TP01/P05/img/7c27ec34-4ec2-09ac-de29-aa514a30772a.png new file mode 100644 index 0000000000000000000000000000000000000000..10de7e9b750f0b6400d36b4e89cd9cc5021be6e3 Binary files /dev/null and b/TP/TP01/P05/img/7c27ec34-4ec2-09ac-de29-aa514a30772a.png differ diff --git a/TP/TP01/P05/img/86ae6435-0fa1-a536-2439-e635f1606fa1.png b/TP/TP01/P05/img/86ae6435-0fa1-a536-2439-e635f1606fa1.png new file mode 100644 index 0000000000000000000000000000000000000000..3b658a7b27ef68d70f46c8a97447a30e31f928b0 Binary files /dev/null and b/TP/TP01/P05/img/86ae6435-0fa1-a536-2439-e635f1606fa1.png differ diff --git a/TP/TP01/P05/img/879ecee9-00a7-fdcd-df0d-5064a975f45e.png b/TP/TP01/P05/img/879ecee9-00a7-fdcd-df0d-5064a975f45e.png new file mode 100644 index 0000000000000000000000000000000000000000..76d0b207fd8d7f705ec068f2c23205b55af4e724 Binary files /dev/null and b/TP/TP01/P05/img/879ecee9-00a7-fdcd-df0d-5064a975f45e.png differ diff --git a/TP/TP01/P05/img/8f7f1ecc-209c-441c-0085-134fe4149974.png b/TP/TP01/P05/img/8f7f1ecc-209c-441c-0085-134fe4149974.png new file mode 100644 index 0000000000000000000000000000000000000000..5d52747d6eac6de2c3f8793a06a16127c8bbb8e4 Binary files /dev/null and b/TP/TP01/P05/img/8f7f1ecc-209c-441c-0085-134fe4149974.png differ diff --git a/TP/TP01/P05/img/937accb2-2984-b27a-4773-8006ee4f5cbf.png b/TP/TP01/P05/img/937accb2-2984-b27a-4773-8006ee4f5cbf.png new file mode 100644 index 0000000000000000000000000000000000000000..7cb630bdd18312c10214ce4b1879cfd307d8b120 Binary files /dev/null and b/TP/TP01/P05/img/937accb2-2984-b27a-4773-8006ee4f5cbf.png differ diff --git a/TP/TP01/P05/img/c70af604-3703-1c9e-a874-d3f25434a0af.png b/TP/TP01/P05/img/c70af604-3703-1c9e-a874-d3f25434a0af.png new file mode 100644 index 0000000000000000000000000000000000000000..bbe5769c636705dfc2b5e8de076b40b2e96e4887 Binary files /dev/null and b/TP/TP01/P05/img/c70af604-3703-1c9e-a874-d3f25434a0af.png differ diff --git a/TP/TP01/P05/img/cursor-pause.png b/TP/TP01/P05/img/cursor-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9c93cc142f4326a188eafc3c0fe96f2975dcab0c Binary files /dev/null and b/TP/TP01/P05/img/cursor-pause.png differ diff --git a/TP/TP01/P05/img/cursor.png b/TP/TP01/P05/img/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..5b4a20e63078ce18bb11a4e601a1994b261522ef Binary files /dev/null and b/TP/TP01/P05/img/cursor.png differ diff --git a/TP/TP01/P05/img/d0a0106a-1ab7-84b8-7288-16f3157ab0b5.png b/TP/TP01/P05/img/d0a0106a-1ab7-84b8-7288-16f3157ab0b5.png new file mode 100644 index 0000000000000000000000000000000000000000..192fbbccf436fdb4ccc9b9140139af9971f81309 Binary files /dev/null and b/TP/TP01/P05/img/d0a0106a-1ab7-84b8-7288-16f3157ab0b5.png differ diff --git a/TP/TP01/P05/img/d45eafbf-4984-698e-3e8a-da3623a0ec58.png b/TP/TP01/P05/img/d45eafbf-4984-698e-3e8a-da3623a0ec58.png new file mode 100644 index 0000000000000000000000000000000000000000..aa07f938e7cd0b12f024a8f84764be869a0b12a3 Binary files /dev/null and b/TP/TP01/P05/img/d45eafbf-4984-698e-3e8a-da3623a0ec58.png differ diff --git a/TP/TP01/P05/img/f579b961-95d6-c335-ce0a-7c3d96400b6a.png b/TP/TP01/P05/img/f579b961-95d6-c335-ce0a-7c3d96400b6a.png new file mode 100644 index 0000000000000000000000000000000000000000..f1b0db3546abd89057810aceb1b221b7d692426f Binary files /dev/null and b/TP/TP01/P05/img/f579b961-95d6-c335-ce0a-7c3d96400b6a.png differ diff --git a/TP/TP01/P05/index.html b/TP/TP01/P05/index.html new file mode 100644 index 0000000000000000000000000000000000000000..b198ce829b296a8db0c377abcfd75b764dcf9309 --- /dev/null +++ b/TP/TP01/P05/index.html @@ -0,0 +1,542 @@ +<!DOCTYPE html> + +<html lang="en"> + +<head> +<title>Dahu Presentation +</title> +<meta charset="utf-8"> +<script src="http://code.jquery.com/jquery-1.9.1.min.js" type="text/javascript"> +</script> +<script src="parse-search.js" type="text/javascript"> +</script> + +<link rel="stylesheet" href="dahuapp.viewer.css"><style>.s0-o2{background-color: #FFFFDD;width: 240px} +.s1-o2{background-color: #FFFFDD;width: 240px} +.s3-o2{background-color: #FFFFDD;width: 240px} +.s4-o2{background-color: #FFFFDD;width: 240px} +.s5-o2{background-color: #FFFFDD;width: 240px} +.s6-o2{background-color: #FFFFDD;width: 240px} +.s7-o2{background-color: #FFFFDD;width: 240px} +.s8-o2{background-color: #FFFFDD;width: 240px} +.s9-o2{background-color: #FFFFDD;width: 240px} +.s10-o2{background-color: #FFFFDD;width: 240px} +.s11-o2{background-color: #FFFFDD;width: 240px} +.s12-o2{background-color: #FFFFDD;width: 240px} +.s13-o2{background-color: #FFFFDD;width: 240px} +.s14-o2{background-color: #FFFFDD;width: 240px} +.s15-o2{background-color: #FFFFDD;width: 240px} +</style> +</head> + +<body> + +<div id="my-dahu-presentation"> + +<div id="loading">Loading presentation... +</div> + +<div class="object-list" style="display: none"> +<img src="img/014336b3-9a2a-1817-25b9-50ff3ccbccd4.png" alt="img/014336b3-9a2a-1817-25b9-50ff3ccbccd4.png" class="background 014336b3-9a2a-1817-25b9-50ff3ccbccd40"> + +<div class="tooltip s0-o2">Ouvrir les paramètres du bloc Integrator. +</div> +<img src="img/00ac7398-6f83-2ebc-85e3-1feb000bc364.png" alt="img/00ac7398-6f83-2ebc-85e3-1feb000bc364.png" class="background 00ac7398-6f83-2ebc-85e3-1feb000bc3640"> + +<div class="tooltip s1-o2">Indiquer que la valeur initiale est donnée à l'extérieur du bloc. +</div> +<img src="img/537c2394-0d22-e637-7dc9-4dcefe8ffb78.png" alt="img/537c2394-0d22-e637-7dc9-4dcefe8ffb78.png" class="background 537c2394-0d22-e637-7dc9-4dcefe8ffb780"> +<img src="img/d45eafbf-4984-698e-3e8a-da3623a0ec58.png" alt="img/d45eafbf-4984-698e-3e8a-da3623a0ec58.png" class="background d45eafbf-4984-698e-3e8a-da3623a0ec580"> + +<div class="tooltip s3-o2">Un port x0 supplémentaire apparait sur le bloc Integrator. +</div> +<img src="img/d0a0106a-1ab7-84b8-7288-16f3157ab0b5.png" alt="img/d0a0106a-1ab7-84b8-7288-16f3157ab0b5.png" class="background d0a0106a-1ab7-84b8-7288-16f3157ab0b50"> + +<div class="tooltip s4-o2">Sélectionner le bloc Constant dans la boite à outils Simulink. +</div> +<img src="img/c70af604-3703-1c9e-a874-d3f25434a0af.png" alt="img/c70af604-3703-1c9e-a874-d3f25434a0af.png" class="background c70af604-3703-1c9e-a874-d3f25434a0af0"> + +<div class="tooltip s5-o2">Déposer un bloc Constant dans votre modèle. +</div> +<img src="img/86ae6435-0fa1-a536-2439-e635f1606fa1.png" alt="img/86ae6435-0fa1-a536-2439-e635f1606fa1.png" class="background 86ae6435-0fa1-a536-2439-e635f1606fa10"> + +<div class="tooltip s6-o2">Connecter la sortie du bloc Constant à l'entrée x0 du bloc Integrator. +</div> +<img src="img/4233bd5f-4100-b71d-e0e8-99a696a682f4.png" alt="img/4233bd5f-4100-b71d-e0e8-99a696a682f4.png" class="background 4233bd5f-4100-b71d-e0e8-99a696a682f40"> + +<div class="tooltip s7-o2">Ouvrir les paramètres du bloc Constant. Choisir la valeur -1. +</div> +<img src="img/f579b961-95d6-c335-ce0a-7c3d96400b6a.png" alt="img/f579b961-95d6-c335-ce0a-7c3d96400b6a.png" class="background f579b961-95d6-c335-ce0a-7c3d96400b6a0"> + +<div class="tooltip s8-o2">Démarrer la simulation. +</div> +<img src="img/40772f5f-7b7e-ea5b-18a7-dbeecc8d5774.png" alt="img/40772f5f-7b7e-ea5b-18a7-dbeecc8d5774.png" class="background 40772f5f-7b7e-ea5b-18a7-dbeecc8d57740"> + +<div class="tooltip s9-o2">Mettre à l'échelle l'écran de l'oscilloscope. Observer que le résultat est identique à l'étape précédente. +</div> +<img src="img/58f2a040-93d0-140f-ad3b-f16229898b92.png" alt="img/58f2a040-93d0-140f-ad3b-f16229898b92.png" class="background 58f2a040-93d0-140f-ad3b-f16229898b920"> + +<div class="tooltip s10-o2">Ouvrir la fenêtre MatLab. +</div> +<img src="img/7c27ec34-4ec2-09ac-de29-aa514a30772a.png" alt="img/7c27ec34-4ec2-09ac-de29-aa514a30772a.png" class="background 7c27ec34-4ec2-09ac-de29-aa514a30772a0"> + +<div class="tooltip s11-o2">Créer une variable V0 de valeur -1. +</div> +<img src="img/879ecee9-00a7-fdcd-df0d-5064a975f45e.png" alt="img/879ecee9-00a7-fdcd-df0d-5064a975f45e.png" class="background 879ecee9-00a7-fdcd-df0d-5064a975f45e0"> + +<div class="tooltip s12-o2">Ouvrir la fenêtre Simulink. Ouvrir les paramètres du bloc Constant. +</div> +<img src="img/135e6dd3-3dee-7be0-6d6c-3407ce073d0e.png" alt="img/135e6dd3-3dee-7be0-6d6c-3407ce073d0e.png" class="background 135e6dd3-3dee-7be0-6d6c-3407ce073d0e0"> + +<div class="tooltip s13-o2">Choisir la variable V0 comme valeur du bloc Constant. +</div> +<img src="img/8f7f1ecc-209c-441c-0085-134fe4149974.png" alt="img/8f7f1ecc-209c-441c-0085-134fe4149974.png" class="background 8f7f1ecc-209c-441c-0085-134fe41499740"> + +<div class="tooltip s14-o2">Démarrer la simulation. +</div> +<img src="img/937accb2-2984-b27a-4773-8006ee4f5cbf.png" alt="img/937accb2-2984-b27a-4773-8006ee4f5cbf.png" class="background 937accb2-2984-b27a-4773-8006ee4f5cbf0"> + +<div class="tooltip s15-o2">Mettre à l'échelle l'écran de l'oscilloscope. Observer que le résultat est identique à l'étape précédente. +</div> + +<div class="mouse-cursor"> +<img src="img/cursor.png" alt="img/cursor.png" class="mouse-cursor-normal"> +<img src="img/cursor-pause.png" alt="img/cursor-pause.png" style="display: none" class="mouse-cursor-pause"> +</div> +</div> + +<div class="control" style="top: 616px;"> +<button class="previous">Previous +</button> +<button class="next">Next +</button> +</div> +</div> +<script src="dahuapp.js" type="text/javascript"> +</script> +<script src="dahuapp.viewer.js" type="text/javascript"> +</script> +<script type="text/javascript">(function($) { + var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams); + myPresentation.load({ + "metaData": { + "imageWidth": 800, + "imageHeight": 600, + "initialBackgroundId": "014336b3-9a2a-1817-25b9-50ff3ccbccd40", + "initialMouseX": 0.25, + "initialMouseY": 0.44555555555555554 + }, + "action": [ + { + "id": "33", + "type": "appear", + "target": "s0-o2", + "trigger": "afterPrevious", + "abs": 0.2833333333333333, + "ord": 0.16375, + "duration": 400 + }, + { + "id": "3", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3840277777777778, + "finalOrd": 0.3055555555555556, + "speed": 0.8 + }, + { + "id": "4", + "type": "appear", + "target": "00ac7398-6f83-2ebc-85e3-1feb000bc3640", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "34", + "type": "appear", + "target": "s1-o2", + "trigger": "afterPrevious", + "abs": 0.36833333333333335, + "ord": 0.135, + "duration": 400 + }, + { + "id": "5", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3798611111111111, + "finalOrd": 0.6866666666666666, + "speed": 0.8 + }, + { + "id": "6", + "type": "appear", + "target": "537c2394-0d22-e637-7dc9-4dcefe8ffb780", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "7", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.6583333333333333, + "finalOrd": 0.42, + "speed": 0.8 + }, + { + "id": "8", + "type": "appear", + "target": "d45eafbf-4984-698e-3e8a-da3623a0ec580", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "35", + "type": "appear", + "target": "s3-o2", + "trigger": "afterPrevious", + "abs": 0.28, + "ord": 0.1575, + "duration": 400 + }, + { + "id": "9", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.8986111111111111, + "finalOrd": 0.24222222222222223, + "speed": 0.8 + }, + { + "id": "10", + "type": "appear", + "target": "d0a0106a-1ab7-84b8-7288-16f3157ab0b50", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "36", + "type": "appear", + "target": "s4-o2", + "trigger": "afterPrevious", + "abs": 0.4166666666666667, + "ord": 0.12125, + "duration": 400 + }, + { + "id": "11", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.1701388888888889, + "finalOrd": 0.5255555555555556, + "speed": 0.8 + }, + { + "id": "12", + "type": "appear", + "target": "c70af604-3703-1c9e-a874-d3f25434a0af0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "37", + "type": "appear", + "target": "s5-o2", + "trigger": "afterPrevious", + "abs": 0.295, + "ord": 0.16625, + "duration": 400 + }, + { + "id": "13", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.1840277777777778, + "finalOrd": 0.5266666666666666, + "speed": 0.8 + }, + { + "id": "14", + "type": "appear", + "target": "86ae6435-0fa1-a536-2439-e635f1606fa10", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "38", + "type": "appear", + "target": "s6-o2", + "trigger": "afterPrevious", + "abs": 0.285, + "ord": 0.165, + "duration": 400 + }, + { + "id": "15", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.22291666666666668, + "finalOrd": 0.5055555555555555, + "speed": 0.8 + }, + { + "id": "16", + "type": "appear", + "target": "4233bd5f-4100-b71d-e0e8-99a696a682f40", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "39", + "type": "appear", + "target": "s7-o2", + "trigger": "afterPrevious", + "abs": 0.32166666666666666, + "ord": 0.07125, + "duration": 400 + }, + { + "id": "17", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2902777777777778, + "finalOrd": 0.10222222222222223, + "speed": 0.8 + }, + { + "id": "18", + "type": "appear", + "target": "f579b961-95d6-c335-ce0a-7c3d96400b6a0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "40", + "type": "appear", + "target": "s8-o2", + "trigger": "afterPrevious", + "abs": 0.19333333333333333, + "ord": 0.08125, + "duration": 400 + }, + { + "id": "19", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.1486111111111111, + "finalOrd": 0.6622222222222223, + "speed": 0.8 + }, + { + "id": "20", + "type": "appear", + "target": "40772f5f-7b7e-ea5b-18a7-dbeecc8d57740", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "41", + "type": "appear", + "target": "s9-o2", + "trigger": "afterPrevious", + "abs": 0.22166666666666668, + "ord": 0.2875, + "duration": 400 + }, + { + "id": "21", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.39166666666666666, + "finalOrd": 0.43555555555555553, + "speed": 0.8 + }, + { + "id": "22", + "type": "appear", + "target": "58f2a040-93d0-140f-ad3b-f16229898b920", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "42", + "type": "appear", + "target": "s10-o2", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 400 + }, + { + "id": "23", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.39166666666666666, + "finalOrd": 0.43555555555555553, + "speed": 0.8 + }, + { + "id": "24", + "type": "appear", + "target": "7c27ec34-4ec2-09ac-de29-aa514a30772a0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "43", + "type": "appear", + "target": "s11-o2", + "trigger": "afterPrevious", + "abs": 0.22166666666666668, + "ord": 0.14, + "duration": 400 + }, + { + "id": "25", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.17291666666666666, + "finalOrd": 0.5344444444444445, + "speed": 0.8 + }, + { + "id": "26", + "type": "appear", + "target": "879ecee9-00a7-fdcd-df0d-5064a975f45e0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "44", + "type": "appear", + "target": "s12-o2", + "trigger": "afterPrevious", + "abs": 0.22, + "ord": 0.20875, + "duration": 400 + }, + { + "id": "27", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2263888888888889, + "finalOrd": 0.5055555555555555, + "speed": 0.8 + }, + { + "id": "28", + "type": "appear", + "target": "135e6dd3-3dee-7be0-6d6c-3407ce073d0e0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "45", + "type": "appear", + "target": "s13-o2", + "trigger": "afterPrevious", + "abs": 0.25166666666666665, + "ord": 0.2225, + "duration": 400 + }, + { + "id": "29", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.28958333333333336, + "finalOrd": 0.09444444444444444, + "speed": 0.8 + }, + { + "id": "30", + "type": "appear", + "target": "8f7f1ecc-209c-441c-0085-134fe41499740", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "46", + "type": "appear", + "target": "s14-o2", + "trigger": "afterPrevious", + "abs": 0.20666666666666667, + "ord": 0.0775, + "duration": 400 + }, + { + "id": "31", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.14305555555555555, + "finalOrd": 0.6611111111111111, + "speed": 0.8 + }, + { + "id": "32", + "type": "appear", + "target": "937accb2-2984-b27a-4773-8006ee4f5cbf0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "47", + "type": "appear", + "target": "s15-o2", + "trigger": "afterPrevious", + "abs": 0.21166666666666667, + "ord": 0.2775, + "duration": 400 + } + ] +}); + myPresentation.start(); +})(jQuery); + +</script> +</body> +</html> \ No newline at end of file diff --git a/TP/TP01/P05/parse-search.js b/TP/TP01/P05/parse-search.js new file mode 100644 index 0000000000000000000000000000000000000000..e7d01c07f6a5d45b9fcabd5d271a8c6cfc5f00e2 --- /dev/null +++ b/TP/TP01/P05/parse-search.js @@ -0,0 +1,14 @@ +// Adapted from http://stackoverflow.com/questions/3234125/creating-array-from-window-location-hash +(function () { + var search = window.location.search.slice(1); + var array = search.split("&"); + + var values, form_data = {}; + + for (var i = 0; i < array.length; i += 1) { + values = array[i].split("="); + form_data[values[0]] = unescape(values[1]); + } + window.getParams = form_data; +}()) + diff --git a/TP/TP01/P06/dahuapp.js b/TP/TP01/P06/dahuapp.js new file mode 100644 index 0000000000000000000000000000000000000000..41c69e9169345a9a6703325d5557a4cc36913e19 --- /dev/null +++ b/TP/TP01/P06/dahuapp.js @@ -0,0 +1,880 @@ +"use strict"; + +/** + * Dahuapp core module. + * + * @param window window javascript object. + * @param $ jQuery + * @returns dahuapp core module. + */ +(function (window, $) { + var dahuapp = (function () { + + var self = {}; + + /* private API */ + + var DahuScreencastGenerator = function () { + + /* + * Format the specified string in a readable format. + */ + function htmlFormat(htmlString) { + var i; + var readableHTML = htmlString; + var lb = '\n'; + var htags = ["<html", "</html>", "</head>", "<title", "</title>", "<meta", "<link", "</body>"]; + for (i = 0; i < htags.length; ++i) { + var hhh = htags[i]; + readableHTML = readableHTML.replace(new RegExp(hhh, 'gi'), lb + hhh); + } + var btags = ["</div>", "</section>", "</span>", "<br>", "<br />", "<blockquote", "</blockquote>", "<ul", "</ul>", "<ol", "</ol>", "<li", "<\!--", "<script", "</script>"]; + for (i = 0; i < btags.length; ++i) { + var bbb = btags[i]; + readableHTML = readableHTML.replace(new RegExp(bbb, 'gi'), lb + bbb); + } + var ftags = ["<img", "<legend", "</legend>", "<button", "</button>"]; + for (i = 0; i < ftags.length; ++i) { + var fff = ftags[i]; + readableHTML = readableHTML.replace(new RegExp(fff, 'gi'), lb + fff); + } + var xtags = ["<body", "<head", "<div", "<section", "<span", "<p"]; + for (i = 0; i < xtags.length; ++i) { + var xxx = xtags[i]; + readableHTML = readableHTML.replace(new RegExp(xxx, 'gi'), lb + lb + xxx); + } + return readableHTML; + } + + /* + * Generates the html header. + */ + var generateHtmlHeader = function ($generated, cssGen) { + $('head', $generated) + .append($(document.createElement('title')) + .append("Dahu Presentation"))/* TODO: make this customizable */ + .append($(document.createElement('meta')) + .attr({'charset': 'utf-8'})) + .append($(document.createElement('script')) + .attr({'src': 'http://code.jquery.com/jquery-1.9.1.min.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'parse-search.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('link')) + .attr({'rel': 'stylesheet', 'href': 'dahuapp.viewer.css'})) + .append($(document.createElement('style')) + .append(cssGen)); + }; + + /* + * Generates the objects. + */ + + var generateHtmlBackgroundImage = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('img')) + .attr({'src': object.img, 'alt': object.img, 'class': 'background ' + object.id})); + }; + var generateHtmlTooltip = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'tooltip ' + object.id}) + .append(object.text)); + }; + + var generateCssTooltip = function ($generated, object) { + var style = []; + + if( object.color != null ) { + style.push('background-color: ' + object.color); + } + if( object.width != null ) { + style.push('width: ' + object.width); + } + + if( style.length != 0 ) { + $generated.append( + '.' + object.id + '{' + style.join(';') + '}\n'); + } + + return $generated; + }; + + /* + * Returns the code used to call the viewer to the presentation. + */ + var getBasicCallCode = function (jsonModel) { + var code = '(function($) {\n'; + code += ' var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams);\n'; + code += ' myPresentation.load(' + jsonModel + ');\n'; + code += ' myPresentation.start();\n'; + code += '})(jQuery);\n'; + return code; + }; + + /* + * Generates the html body. + */ + var generateHtmlBody = function ($generated, jsonModel, jsonGen) { + $('body', $generated) + /* We could use a <section> here too, but it does not work with MS IE 8. + Alternatively, adding this in the header would work: + + <!--[if lt IE 9]> + <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + */ + .append($(document.createElement('div')) + .attr({'id': 'my-dahu-presentation'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.viewer.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'type': 'text/javascript'}) + .append(getBasicCallCode(jsonGen))); + $('#my-dahu-presentation', $generated) + .append($(document.createElement('div')) + .attr({'id': 'loading'}).append("Loading presentation...")) + .append($(document.createElement('div')) + .attr({'class': 'object-list', + 'style': 'display: none'})) + .append($(document.createElement('div')) + .attr({'class': 'control'})); + + /* Adding the objects to the page */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "background": + generateHtmlBackgroundImage($generated, object); + break; + case "tooltip": + generateHtmlTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + /* Warning here, i'm not sure if $.each is always over, here */ + + /* Adding the control buttons to the page */ + $('.control', $generated) + .css({'top': (jsonModel.getImageHeight() + 16) + 'px'}) + .append($(document.createElement('button')) + .attr({'class': 'previous'}) + .append('Previous')) + .append($(document.createElement('button')) + .attr({'class': 'next'}) + .append('Next')); + + /* Adding the mouse cursor image */ + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'mouse-cursor'}) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor.png', 'alt': 'img/cursor.png', 'class': 'mouse-cursor-normal'})) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor-pause.png', 'alt': 'img/cursor-pause.png', + 'style': 'display: none', 'class': 'mouse-cursor-pause'}))); + }; + + /* + * Generates the css String with the Json model. + */ + this.generateCssString = function (jsonModel) { + var $generated = $('<style></style>'); + + /* Going through each object */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "tooltip": + generateCssTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + return $generated.text(); + } + + /* + * Generates the html String with the Json model. + */ + this.generateHtmlString = function (jsonModel, jsonGen, cssGen) { + /* Initialising the compilation area */ + var $generated = $(document.createElement('div')); + + /* We create the html using the json */ + $generated.append($(document.createElement('html')) + .attr({'lang': 'en'})); + $('html', $generated) + .append($(document.createElement('head'))) + .append($(document.createElement('body'))); + + generateHtmlHeader($generated, cssGen); + generateHtmlBody($generated, jsonModel, jsonGen); + + var result = htmlFormat($generated.html()); + + return '<!DOCTYPE html>\n' + result; + }; + + /* + * Generates the generated JSON using the JSONmodel. + * @param {object} jsonModel The json model to transform. + * @param {java.awt.Dimension} imgDim The dimension of images. + */ + this.generateJsonString = function (jsonModel, imgDim) { + var generated = self.createScreencastGeneratedModel(); + generated.setImageSize(imgDim.width, imgDim.height); + generated.setInitialBackground(jsonModel.getInitialBackground()); + generated.setInitialMousePos(jsonModel.getInitialMousePos()); + for (var i = 0; i < jsonModel.getNbSlide(); i++) { + var actionList = jsonModel.getActionList(i); + for (var j = 0; j < actionList.length; j++) { + /* + * We don't add the two first actions of the first slide + * because they are present in the presentation metadata. + * It corresponds to the mouse initial pos and first background. + */ + if (i > 0 || j > 1) { + generated.addAction(actionList[j], imgDim.width, imgDim.height); + } + } + } + return generated.getJson(); + }; + }; + + /* + * Model for a JSON object that will only be used by the viewer, never + * saved on a file, used to transform the properties of actions + * specified on the JSON file of a presentation to executable + * functions for each action. + */ + var DahuScreencastExecutableModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* + * Creates a functions representing the specified action, and adds + * it to this object. + * @param {object} action + */ + var addExecutableAction = function (action) { + var executableAction = { + 'id': action.id, + 'trigger': action.trigger, + 'target': action.target, + 'delayAfter': action.delayAfter, + 'doneFunction': function (events, selector) { + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.delayAfter); + } + }; + if (executableAction.delayAfter == null) { + executableAction.delayAfter = 200; + } + switch (action.type.toLowerCase()) { + case "appear": + executableAction.abs = (action.abs * json.metaData.imageWidth) + 'px'; + executableAction.ord = (action.ord * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(); + }; + break; + case "disappear": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + $(selector + ' .' + this.target).hide(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).show(); + }; + executableAction.executeImmediately = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + break; + case "move": + executableAction.finalAbs = (action.finalAbs * json.metaData.imageWidth) + 'px'; + executableAction.finalOrd = (action.finalOrd * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.speed = action.speed; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + if (this.duration == null) { + var initialAbsPix = this.initialAbs.replace('px', ''); + var initialOrdPix = this.initialOrd.replace('px', ''); + var finalAbsPix = this.finalAbs.replace('px', ''); + var finalOrdPix = this.finalOrd.replace('px', ''); + var distance = Math.sqrt(Math.pow(finalAbsPix - initialAbsPix, 2) + + Math.pow(finalOrdPix - initialOrdPix, 2)); + if (!this.speed) { + this.speed = .8; // in pixel per milisecond: fast, but not too much. + } + this.duration = distance + this.speed; + if (this.duration < 200) { // Slow down a bit for short distances. + this.duration = 200; + } + } + $(sel).animate({ + 'left': this.finalAbs, + 'top': this.finalOrd + }, this.duration, 'linear', function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).css({ + 'left': this.initialAbs, + 'top': this.initialOrd + }); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + $(sel).css({ + 'left': this.finalAbs, + 'top': this.finalOrd + }); + }; + break; + case "delay": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.duration); + }; + executableAction.executeReverse = function (selector) { + // Nothing! + }; + executableAction.executeImmediately = function (selector) { + // Nothing too! + }; + break; + } + json.action.push(executableAction); + }; + + /* Public API */ + + /* + * Loads the specified JSON read from a 'presentation.json' file, + * and stores the functions representing each actions in an object. + * @param {object} jsonToLoad + */ + this.loadJson = function (jsonToLoad) { + json.metaData = jsonToLoad.metaData; + for (var i = 0; i < jsonToLoad.action.length; i++) { + addExecutableAction(jsonToLoad.action[i]); + } + }; + + /* + * Returns the object containing the functions. + */ + this.getJson = function () { + return json; + }; + }; + + /* + * Used to transform the 'dahu' file to a JSON file used by the viewer, + * which only contains some metaData and a list of actions. + */ + var DahuScreencastGeneratedModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* Public API */ + + /* + * Returns a string representation of this json. + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * Setters for the generated json metadata. + */ + this.setImageSize = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + this.setInitialMousePos = function (pos) { + json.metaData.initialMouseX = pos.x; + json.metaData.initialMouseY = pos.y; + }; + + this.setInitialBackground = function (id) { + json.metaData.initialBackgroundId = id; + }; + + this.addAction = function (action) { + json.action.push(action); + }; + + /* + * Transforms a JSON containing action properties to a JSON containing + * the execution functions. + * @param {Object} json + * @returns {Object} A json object containing the execution functions + * for all the actions of the presentation. + */ + this.toExecutableList = function (json) { + var executableList = { + metaData: json.metaData, + action: new Array() + }; + for (var i = 0; i < json.action.length; i++) { + addExecutableAction(executableList, json.action[i]); + } + return executableList; + }; + }; + + /* + * Represents a 'dahu' file for a project. + */ + var DahuScreencastModel = function () { + + /* Private API */ + + var json = {}; + + /* + * Generates a unique action ID. + * + * With this implementation, this ID is unique as long as the user + * doesn't replace it manually with a not kind value or replace + * the nextUniqueId with bad intentions. + * But maybe that a UUID is a bit tiresome to put as an anchor... + */ + var generateUniqueActionId = function () { + json.metaData.nextUniqueId++; + return json.metaData.nextUniqueId.toString(); + }; + + /* + * This method checks if the json representing a dahu project is + * in the good version. It's in case a project file was created + * with a previous version of Dahu, and that some fields are + * missing. + * + * It doesn't control each field (at the moment) but only the + * fields that can be missing due to a new Dahu version and not + * to a manual editing. + * + * This method doesn't check any Json syntax or something like that. + */ + var upgradeJsonVersion = function () { + // Checks if unique IDs are in the project file + if (!json.metaData.nextUniqueId) { + var currentId = 0; + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].action.length; j++) { + json.data[i].action[j].id = currentId.toString(); + currentId++; + } + } + json.metaData.nextUniqueId = currentId; + } + }; + + /* Public API */ + + /* + * json variable generated from a JSON file. + * @param String stringJson String loaded from JSON file. + */ + this.loadJson = function (stringJson) { + json = JSON.parse(stringJson); + upgradeJsonVersion(); + }; + + /* + * Create a new presentation variable in the JSON file which will contain slides. + */ + this.createPresentation = function (width, height) { + json.metaData = {}; + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + json.metaData.nextUniqueId = 0; + json.data = new Array(); + }; + + /* + * Add a new slide in the presentation variable of the JSON file. + * @param int index wanted for the slide. + * @param String idSlide Unique identifier for the slide. + * @param String img Related to pathname of the image. + * @param double mouseX Abscissa mouse position in %. + * @param double mouseY Ordinate mouse position in %. + * @return Index of the newly added slide. + */ + this.addSlide = function (indexSlide, idSlide, img, mouseX, mouseY, speed) { + var slide = { + "object": new Array(), + "action": new Array() + }; + json.data.splice(indexSlide, 0, slide); + this.addObject(indexSlide, "background", idSlide, img); + this.addObject(indexSlide, "mouse"); + this.addAction(indexSlide, "move", json.data[indexSlide].object[1].id, "onClick", mouseX, mouseY, speed); + this.addAction(indexSlide, "appear", json.data[indexSlide].object[0].id, "afterPrevious"); + }; + + /* + * Object factory. + * Add a new Object in the slide idSlide. + * @param int idSlide + * @param string type + * Other params can be specified depending on the object's type. + */ + this.addObject = function (idSlide, type) { + var object = { + "type": type + }; + switch (type.toLowerCase()) { + case "background": + object.id = arguments[2] + json.data[idSlide].object.length; + object.img = arguments[3] || ""; + break; + case "mouse": + object.id = "mouse-cursor"; + break; + case "tooltip": + /* + * TODO: we'll need a more robust unique name + * when we start actually using this. + */ + object.id = "s" + idSlide + "-o" + json.data[idSlide].object.length; + object.text = arguments[2] || ""; + object.color = arguments[3] || null; + object.width = arguments[4] || ""; + json.data[idSlide].object.push(object); + var objectLength = json.data[idSlide].object.length; + var last = json.data[idSlide].object[objectLength-1]; + json.data[idSlide].object[objectLength-1] = + json.data[idSlide].object[objectLength-2]; + json.data[idSlide].object[objectLength-2] = last; + break; + } + if(type.toLowerCase() != "tooltip"){ + json.data[idSlide].object.push(object); + } + }; + + /* + * Action factory. + * Add a new Action in the slide idSlide whose target is the id of an object. + * Three types of trigger : "withPrevious", "afterPrevious", "onClick". + * @param int idSlide + * @param string type + * @param string target + * @param string trigger + * Other params can be specified depending on the object's type. + */ + this.addAction = function (idSlide, type, target, trigger) { + var action = { + "id": generateUniqueActionId(), + "type": type, + "target": target, + "trigger": trigger + }; + switch (type.toLowerCase()) { + case "appear": + action.abs = arguments[4] || 0.0; + action.ord = arguments[5] || 0.0; + action.duration = arguments[6] || 0; + break; + case "disappear": + action.duration = arguments[4] || 0; + break; + case "move": + action.finalAbs = arguments[4] || 0.0; + action.finalOrd = arguments[5] || 0.0; + action.speed = arguments[6] || 0; + break; + } + json.data[idSlide].action.push(action); + }; + + this.editMouse = function (idSlide, idAction, mouseX, mouseY) { + json.data[idSlide].action[idAction].finalAbs = mouseX; + json.data[idSlide].action[idAction].finalOrd = mouseY; + }; + + /* + * Sets a title for the presentation. + * @param String title Title to set. + */ + this.setTitle = function (title) { + json.metaData.title = title; + }; + + /* + * Sets an annotation for the presentation. + * @param String annotation Annotation to set. + */ + this.setAnnotation = function (annotation) { + json.metaData.annotation = annotation; + }; + + /* + * Inverts the two slides (their positions on the table). + * @param int idSlide1 Index of the first slide. + * @param int idSlide2 Index of the second slide. + */ + this.invertSlides = function (idSlide1, idSlide2) { + var tmp = json.data[idSlide1]; + json.data[idSlide1] = json.data[idSlide2]; + json.data[idSlide2] = tmp; + }; + + /* + * Inverts the two actions (their positions on the table). + * @param int idSlide + * @param int idAction1 + * @param int idAction2 + */ + this.invertActions = function (idSlide, idAction1, idAction2) { + var tmp = json.data[idSlide].action[idAction1]; + json.data[idSlide].action[idAction1] = json.data[idSlide].action[idAction2]; + json.data[idSlide].action[idAction2] = tmp; + }; + + /* + * Returns the actions on the specified slide. + * @returns {Array} + */ + this.getActionList = function (idSlide) { + return json.data[idSlide].action; + }; + + /* + * Catches all the objects of the presentation + * @returns {Array} List of objects of the presentation + */ + this.getObjectList = function () { + var objectList = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + var indexObject = 0; + while (json.data[indexSlide].object[indexObject]) { + objectList.push(json.data[indexSlide].object[indexObject]); + indexObject++; + } + indexSlide++; + } + return objectList; + }; + + /* + * Returns an array containing all the background images. + * @returns {Array} List of background images. + */ + this.getImageList = function () { + var list = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + list.push(json.data[indexSlide].object[0].img); + indexSlide++; + } + ; + return list; + }; + + /* + * Returns an object containing the id of the first background. + * @returns {string} Id of the first background. + */ + this.getInitialBackground = function () { + return json.data[0].object[0].id; + }; + + /* + * Returns an object containing the initial mouse position. + * @returns {object} Initial position of mouse. + */ + this.getInitialMousePos = function () { + var pos = {}; + pos.x = json.data[0].action[0].finalAbs; + pos.y = json.data[0].action[0].finalOrd; + return pos; + }; + + /* + * Removes the slide at the specified index. + * @param {int} idSlide + */ + this.removeSlide = function (idSlide) { + json.data.splice(idSlide, 1); + }; + + /* + * Removes the action at the specified slide. + * @param {int} idSlide + * @param {int} idAction + */ + this.removeAction = function (idSlide, idAction) { + json.data[idSlide].action.splice(idAction, 1); + }; + + /* + * Removes the specified object from the slide. + * Also removes all the actions attached to this object. + * @param {int} idSlide + * @param {int} idObject + */ + this.removeObject = function (idSlide, idObject) { + var removed = json.data[idSlide].object.splice(idObject, 1); + for (var i = 0; i < json.data.length; i++) { + var j = 0; + while (json.data[i].action[j]) { + if (json.data[i].action[j].target === removed.id) { + json.data[i].action.splice(j, 1); + } else { + j++; + } + } + } + }; + + /* + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * @returns {String} returns the index for the next slide. + */ + this.getNbSlide = function () { + return json.data.length; + }; + + /* + * @return {object} returns the object identified by idSlide + */ + this.getSlide = function (idSlide) { + return json.data[idSlide]; + }; + + /* + * Sets the size of images for the generated presentation. + * The parameters can be null : it means there are no + * requirement for this dimension. + * @param {int} width New width for the generated images. + * @param {int} height New height for the generated images. + */ + this.setImageSizeRequirements = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + /* + * Gets the width of images for the generated presentation. + * @return {int or null} Width of generated images. + */ + this.getImageWidth = function () { + return json.metaData.imageWidth; + }; + + /* + * Gets the height of images for the generated presentation. + * @return {int or null} Height of generated images. + */ + this.getImageHeight = function () { + return json.metaData.imageHeight; + }; + + /* + * Gets a background image (no one in particular, the first met). + * @return {string} The name of a background image. + */ + this.getABackgroundImage = function () { + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].object.length; j++) { + if (json.data[i].object[j].type === "background") { + return json.data[i].object[j].img; + } + } + } + return null; + }; + }; + + /* public API */ + + self.version = "0.0.1"; + + self.createScreencastGenerator = function createScreencastGenerator() { + return new DahuScreencastGenerator(); + }; + + self.createScreencastModel = function createScreencastModel() { + return new DahuScreencastModel(); + }; + + self.createScreencastExecutableModel = function createScreencastExecutableModel() { + return new DahuScreencastExecutableModel(); + }; + + self.createScreencastGeneratedModel = function createScreencastGeneratedModel() { + return new DahuScreencastGeneratedModel(); + }; + + return self; + })(); + + window.dahuapp = dahuapp; + +})(window, jQuery); \ No newline at end of file diff --git a/TP/TP01/P06/dahuapp.viewer.css b/TP/TP01/P06/dahuapp.viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ea934576dad6ca9263a6163de58f5fe4534d1f0b --- /dev/null +++ b/TP/TP01/P06/dahuapp.viewer.css @@ -0,0 +1,25 @@ +.object-list { + position: absolute; + margin: 0px; + padding: 0px; +} + +.mouse-cursor { + position: absolute; +} + +.control { + position: relative; +} + +.background { + position: absolute; +} + +.tooltip { + position: absolute; + width: 100px; + padding: 4px; + margin: 2px; + border: 2px black solid; +} \ No newline at end of file diff --git a/TP/TP01/P06/dahuapp.viewer.js b/TP/TP01/P06/dahuapp.viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..12ad03b2cdc503a8fd6ff3f5fdc2a74edbb36edb --- /dev/null +++ b/TP/TP01/P06/dahuapp.viewer.js @@ -0,0 +1,456 @@ +"use strict"; + +/** + * Dahuapp viewer module. + * + * @param dahuapp dahuapp object to augment with module. + * @param $ jQuery + * @returns dahuapp extended with viewer module. + */ + +(function(dahuapp, $) { + var viewer = (function() { + + var self = {}; + + var DahuViewerModel = function(select, getParams) { + + /* Private API */ + + var json = null; + var selector = select; + var parseAutoOption = function(name, defaultValue) { + var res = getParams[name]; + if (res == null) { + if (name == 'auto') { + return false; + } else { + return parseAutoOption('auto', defaultValue); + } + } + if (res.toLowerCase() === 'false') { + return false; + } + res = parseInt(res); + if (isNaN(res)) { + // e.g. ?autoplay or ?autoplay=true + return defaultValue; + } + return res; + } + + /* Whether to wait for "next" event between actions */ + var autoPlay = parseAutoOption('autoplay', 5000); + /* Whether to wait for "next" event on page load */ + var autoStart = parseAutoOption('autostart', 5000); + /* Whether to loop back to start at the end of presentation */ + var autoLoop = parseAutoOption('autoloop', 5000); + + var events = (function() { + var self = {}; + /* + * Creates a generic event. + */ + var createEvent = function() { + var callbacks = $.Callbacks(); + return { + publish: callbacks.fire, + subscribe: callbacks.add, + unsubscribe: callbacks.remove, + unsubscribeAll: callbacks.empty + }; + }; + /* + * Called when the button next is pressed. + */ + self.onNext = createEvent(); + /* + * Called when the button previous is pressed. + */ + self.onPrevious = createEvent(); + /* + * Called when an action is over. + */ + self.onActionOver = createEvent(); + /* + * Called when an action starts. + */ + self.onActionStart = createEvent(); + /* + * Called when at least one action was running and has finished. + */ + self.onAllActionFinish = createEvent(); + + return self; + })(); + + /* + * Variables used like index for methodes subscribed. + */ + var currentAction = 0; /* Action currently running */ + var nextAction = 0; /* Action to execute on 'Next' click */ + var nbActionsRunning = 0; + var previousAnchor = -1; /* Last entered anchor, only used in + * case the 'onhashchange' event is + * not supported by the web browser */ + + /* + * Functions to reinitialise running actions and subscribed + * callbacks (reinitialise is called once without stopping + * all the actions, so the two functions are separated). + */ + var stopAllActions = function() { + $(selector + " .object-list").children().stop(true, true); + reinitialiseCallbackLists(); + nbActionsRunning = 0; + }; + var reinitialiseCallbackLists = function() { + events.onActionStart.unsubscribeAll(); + events.onActionStart.subscribe(onActionStartEventHandler); + events.onAllActionFinish.unsubscribeAll(); + }; + + /* + * Timer used to program onNext event in autoplay mode. + */ + var playTimer = 0; + + /* + * Function used when an "onNextEvent" event is caught. + */ + var onNextEventHandler = function() { + /* + * If the user pressed "next" before an autoplay event + * is triggered, it replaces the autoplay event, hence + * cancels it: + */ + window.clearTimeout(playTimer); + + enterAnimationMode(); + stopAllActions(); + var tmpAction = nextAction; + var onlyWithPrevious = true; + nextAction++; + currentAction = nextAction; + while (json.action[currentAction] && onlyWithPrevious) { + switch (json.action[currentAction].trigger) { + case 'onClick': + nextAction = currentAction; + onlyWithPrevious = false; + break; + case 'withPrevious': + var tmp = currentAction; + /* + * We can't directly pass 'execute' as callback because we + * allow the 'execute' function to reference a property of the + * object (by using 'this.property') so we have to call the + * function in the containing object to make that available + */ + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + while (json.action[nextAction] && json.action[nextAction].trigger !== 'onClick') { + nextAction++; + } + onlyWithPrevious = false; + break; + } + currentAction++; + } + if (json.action[tmpAction]) { + launch(json.action[tmpAction]); + } + if (nextAction > json.action.length) { + nextAction = json.action.length; + } + }; + + /* + * Function used when an "onPreviousEvent" event is caught. + */ + var onPreviousEventHandler = function() { + stopAllActions(); + currentAction = nextAction - 1; + while (json.action[currentAction] && json.action[currentAction].trigger !== 'onClick') { + launchReverse(json.action[currentAction]); + currentAction--; + } + /* currentAction = -1 means that it's the beginning */ + if (currentAction > -1) { + launchReverse(json.action[currentAction]); + } + if (currentAction < 0) { + currentAction = 0; + } + nextAction = currentAction; + }; + + /* + * Function used when an "onActionOverEvent" event is caught. + */ + var onActionOverEventHandler = function() { + nbActionsRunning--; + if (nbActionsRunning === 0) { + events.onAllActionFinish.publish(events, selector); + reinitialiseCallbackLists(); + while (json.action[currentAction]) { + switch (json.action[currentAction].trigger) { + case 'onClick': + leaveAnimationMode(); + if (autoPlay && nbActionsRunning === 0) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoPlay); + } + return; + case 'withPrevious': + var tmp = currentAction; + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + currentAction++; + return; + } + currentAction++; + + } + if (autoLoop && nbActionsRunning === 0) { + setTimeout(function () { + resetPresentation(); + startPresentationMaybe(); + }, autoLoop); + } + } + leaveAnimationMode(); + }; + + /* + * Function used when an "onActionStartEvent" event is caught. + */ + var onActionStartEventHandler = function() { + nbActionsRunning++; + }; + + /* + * Enter and leave "animation" mode. The viewer is in + * animation mode when something is going on without human + * interaction (i.e. executing actions before the next + * "onClick"). + */ + var enterAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').hide(); + $(selector + ' .mouse-cursor-normal').show(); + }; + + var leaveAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').show(); + $(selector + ' .mouse-cursor-normal').hide(); + }; + + /* + * Function used to perform actions. + */ + var launch = function(action) { + action.execute(events, selector); + }; + var launchReverse = function(action) { + action.executeReverse(selector); + }; + + /* + * The two following methods each returns an array containing the + * actions to execute to reach the given anchor (respectively + * forward or backwards). + * + * If the given anchor matches none of the actions, then an empty + * array is returned. + */ + var getActionsToJumpForward = function(anchor) { + var actions = new Array(); + for (var i = nextAction; i < json.action.length; i++) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + if (json.action[i].id == anchor) { + return actions; + } else { + actions.push(json.action[i]); + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + var getActionsToJumpBackwards = function(anchor) { + var actions = new Array(); + for (var i = nextAction - 1; i >= 0; i--) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + actions.push(json.action[i]); + if (json.action[i].id == anchor) { + return actions; + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + + /* + * Updates the position of the presentation depending on the + * given anchor (next action wanted). + */ + var jumpToAnchor = function(anchor) { + if (anchor !== '') { + stopAllActions(); + if (anchor > nextAction) { + // forward + var actions = getActionsToJumpForward(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeImmediately(selector); + } + nextAction += actions.length; + } else { + // backwards + var actions = getActionsToJumpBackwards(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeReverse(selector); + } + nextAction -= actions.length; + } + } + }; + + var resetPresentation = function() { + window.clearTimeout(playTimer); + + currentAction = 0; + nextAction = 0; + nbActionsRunning = 0; + + /* + * At the beginning, the visible image is the first one of the presentation + */ + $(selector + " .object-list").children().hide(); + + $(selector + " ." + json.metaData.initialBackgroundId).show(); + + $(selector + " .mouse-cursor").css({ + 'top': (json.metaData.initialMouseY * json.metaData.imageHeight) + "px", + 'left': (json.metaData.initialMouseX * json.metaData.imageWidth) + "px" + }); + + $(selector + " .mouse-cursor").show(); + } + + var startPresentationMaybe = function() { + if (autoStart) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoStart); + } + } + + /* Public API */ + + this.loadUrl = function(url) { + var dataJson; + $.ajax({ + 'async': false, + 'global': false, + 'url': url, + 'dataType': "json", + 'success': function(data) { + dataJson = data; + } + }); + + load(dataJson); + }; + + this.load = function(dataJson) { + /* Transforms data JSON to executable functions for actions */ + var execModel = dahuapp.createScreencastExecutableModel(); + execModel.loadJson(dataJson); + json = execModel.getJson(); + }; + + this.start = function() { + + /* + * Subscription of methods to their events. + */ + events.onNext.subscribe(onNextEventHandler); + events.onPrevious.subscribe(onPreviousEventHandler); + events.onActionOver.subscribe(onActionOverEventHandler); + events.onActionStart.subscribe(onActionStartEventHandler); + + resetPresentation(); + + /* + * If an anchor has been specified, we place the presentation + * in the right position. + */ + jumpToAnchor(window.location.hash.substring(1)); + + /* + * If the anchor changes during the presentation, then the + * presentation is updated + */ + if ("onhashchange" in window) { + // event supported + window.onhashchange = function () { + jumpToAnchor(window.location.hash.substring(1)); + }; + } else { + // event not supported : periodical check + window.setInterval(function () { + if (window.location.hash.substring(1) !== previousAnchor) { + previousAnchor = window.location.hash.substring(1); + jumpToAnchor(window.location.hash.substring(1)); + } + }, 100); + } + + /* + * A click on the "next" button publishes a nextSlide event + */ + $(selector + " .next").click(function() { + events.onNext.publish(); + }); + + /* + * A click on the "previous" button publishes a previousSlide event + */ + $(selector + " .previous").click(function() { + events.onPrevious.publish(); + }); + + /* + * Everything is ready, show the presentation + * (hidden with style="display: none" from HTML). + */ + $("#loading").hide(); + $(selector + " .object-list").show(); + startPresentationMaybe(); + }; + }; + + self.createDahuViewer = function(selector, getParams) { + return new DahuViewerModel(selector, getParams); + }; + + return self; + })(); + + dahuapp.viewer = viewer; +})(dahuapp || {}, jQuery); diff --git a/TP/TP01/P06/img/042b3794-32ee-9789-5a5e-7492c70ea14b.png b/TP/TP01/P06/img/042b3794-32ee-9789-5a5e-7492c70ea14b.png new file mode 100644 index 0000000000000000000000000000000000000000..470dbb11df174b7a238fc959bfcc3b7b046797c5 Binary files /dev/null and b/TP/TP01/P06/img/042b3794-32ee-9789-5a5e-7492c70ea14b.png differ diff --git a/TP/TP01/P06/img/05133e21-8ad0-1342-3568-c459d579b14a.png b/TP/TP01/P06/img/05133e21-8ad0-1342-3568-c459d579b14a.png new file mode 100644 index 0000000000000000000000000000000000000000..443a16dce6d215211225ab83fb731ae64cd1f281 Binary files /dev/null and b/TP/TP01/P06/img/05133e21-8ad0-1342-3568-c459d579b14a.png differ diff --git a/TP/TP01/P06/img/104c2f49-b0ff-9eb6-1993-577584ae77ea.png b/TP/TP01/P06/img/104c2f49-b0ff-9eb6-1993-577584ae77ea.png new file mode 100644 index 0000000000000000000000000000000000000000..b0635c5368ec4e0f148dd533c2d2cb365d5218da Binary files /dev/null and b/TP/TP01/P06/img/104c2f49-b0ff-9eb6-1993-577584ae77ea.png differ diff --git a/TP/TP01/P06/img/146e7fd1-79a9-d471-f996-f583ba0fe8f9.png b/TP/TP01/P06/img/146e7fd1-79a9-d471-f996-f583ba0fe8f9.png new file mode 100644 index 0000000000000000000000000000000000000000..08a8b11f86747b45e6a88e0d4ed947b26c9ef726 Binary files /dev/null and b/TP/TP01/P06/img/146e7fd1-79a9-d471-f996-f583ba0fe8f9.png differ diff --git a/TP/TP01/P06/img/24ac7258-308f-3469-7ff3-73cd1714356b.png b/TP/TP01/P06/img/24ac7258-308f-3469-7ff3-73cd1714356b.png new file mode 100644 index 0000000000000000000000000000000000000000..d6e4db98af50d46bf69565c8266f066de4e36b34 Binary files /dev/null and b/TP/TP01/P06/img/24ac7258-308f-3469-7ff3-73cd1714356b.png differ diff --git a/TP/TP01/P06/img/28cc4893-5425-5aac-05e8-a7e32ca109b8.png b/TP/TP01/P06/img/28cc4893-5425-5aac-05e8-a7e32ca109b8.png new file mode 100644 index 0000000000000000000000000000000000000000..34da5a709ba0a5dc085f7b6eaebb8a48561fa968 Binary files /dev/null and b/TP/TP01/P06/img/28cc4893-5425-5aac-05e8-a7e32ca109b8.png differ diff --git a/TP/TP01/P06/img/2ab20dfd-b528-4e65-28d0-5bbe0ce71d26.png b/TP/TP01/P06/img/2ab20dfd-b528-4e65-28d0-5bbe0ce71d26.png new file mode 100644 index 0000000000000000000000000000000000000000..435b0e8d6bf73c0ad5a42ee859f1610184ab55c6 Binary files /dev/null and b/TP/TP01/P06/img/2ab20dfd-b528-4e65-28d0-5bbe0ce71d26.png differ diff --git a/TP/TP01/P06/img/30445c44-4357-cb29-da5c-dd8a9418ce31.png b/TP/TP01/P06/img/30445c44-4357-cb29-da5c-dd8a9418ce31.png new file mode 100644 index 0000000000000000000000000000000000000000..f556d1e47eabf050f6c00dd6bd79bef0feb5146a Binary files /dev/null and b/TP/TP01/P06/img/30445c44-4357-cb29-da5c-dd8a9418ce31.png differ diff --git a/TP/TP01/P06/img/338b5367-d1f7-58fd-7ac9-8fa9ee456d82.png b/TP/TP01/P06/img/338b5367-d1f7-58fd-7ac9-8fa9ee456d82.png new file mode 100644 index 0000000000000000000000000000000000000000..1fb8547a8cb30fe758c5cea1027d5daa7e283b1d Binary files /dev/null and b/TP/TP01/P06/img/338b5367-d1f7-58fd-7ac9-8fa9ee456d82.png differ diff --git a/TP/TP01/P06/img/37c23d3f-b713-19c2-ff10-7e177eb69c38.png b/TP/TP01/P06/img/37c23d3f-b713-19c2-ff10-7e177eb69c38.png new file mode 100644 index 0000000000000000000000000000000000000000..f6959c7e4bfc5c76c3aec20d2517a3842d290367 Binary files /dev/null and b/TP/TP01/P06/img/37c23d3f-b713-19c2-ff10-7e177eb69c38.png differ diff --git a/TP/TP01/P06/img/44cbf940-d047-a39e-6fee-2d91ef83f91c.png b/TP/TP01/P06/img/44cbf940-d047-a39e-6fee-2d91ef83f91c.png new file mode 100644 index 0000000000000000000000000000000000000000..2e9777084a002873fc76072840163038713c851a Binary files /dev/null and b/TP/TP01/P06/img/44cbf940-d047-a39e-6fee-2d91ef83f91c.png differ diff --git a/TP/TP01/P06/img/46b08559-5496-a26e-c7f2-14ac0a92fecf.png b/TP/TP01/P06/img/46b08559-5496-a26e-c7f2-14ac0a92fecf.png new file mode 100644 index 0000000000000000000000000000000000000000..06c6c8d48a39a003a8822d6698517775b6b47af7 Binary files /dev/null and b/TP/TP01/P06/img/46b08559-5496-a26e-c7f2-14ac0a92fecf.png differ diff --git a/TP/TP01/P06/img/4daad903-6dbe-5e6c-cc1b-12ad9749eb53.png b/TP/TP01/P06/img/4daad903-6dbe-5e6c-cc1b-12ad9749eb53.png new file mode 100644 index 0000000000000000000000000000000000000000..28baa3c9cc2a975ed3abf28d0f49d310d2f109e3 Binary files /dev/null and b/TP/TP01/P06/img/4daad903-6dbe-5e6c-cc1b-12ad9749eb53.png differ diff --git a/TP/TP01/P06/img/4decb081-5029-2428-8d10-d7f6c0808425.png b/TP/TP01/P06/img/4decb081-5029-2428-8d10-d7f6c0808425.png new file mode 100644 index 0000000000000000000000000000000000000000..90626f563b0d0ed7b221a31115cdcb43a68871d4 Binary files /dev/null and b/TP/TP01/P06/img/4decb081-5029-2428-8d10-d7f6c0808425.png differ diff --git a/TP/TP01/P06/img/50450763-9cfc-4865-8c1d-24b1fa9cac8c.png b/TP/TP01/P06/img/50450763-9cfc-4865-8c1d-24b1fa9cac8c.png new file mode 100644 index 0000000000000000000000000000000000000000..4e00f1a91c8e18667328f0c7098ae692466633f2 Binary files /dev/null and b/TP/TP01/P06/img/50450763-9cfc-4865-8c1d-24b1fa9cac8c.png differ diff --git a/TP/TP01/P06/img/571c8ded-4b8d-dfed-d850-b84ae3ec961e.png b/TP/TP01/P06/img/571c8ded-4b8d-dfed-d850-b84ae3ec961e.png new file mode 100644 index 0000000000000000000000000000000000000000..b7c6b7eb9418c45aacafe9fd0c1f748cef6e548b Binary files /dev/null and b/TP/TP01/P06/img/571c8ded-4b8d-dfed-d850-b84ae3ec961e.png differ diff --git a/TP/TP01/P06/img/636bdb73-2612-3933-1f1b-6022d6e33625.png b/TP/TP01/P06/img/636bdb73-2612-3933-1f1b-6022d6e33625.png new file mode 100644 index 0000000000000000000000000000000000000000..c44abbfb45c97dd373c4dbd9a4279b7b2324bae0 Binary files /dev/null and b/TP/TP01/P06/img/636bdb73-2612-3933-1f1b-6022d6e33625.png differ diff --git a/TP/TP01/P06/img/7a1eeb94-4ce9-7b79-aa1f-87d376e76b5c.png b/TP/TP01/P06/img/7a1eeb94-4ce9-7b79-aa1f-87d376e76b5c.png new file mode 100644 index 0000000000000000000000000000000000000000..f77a762a95697ccd946426d5196e6c48c75ee4e7 Binary files /dev/null and b/TP/TP01/P06/img/7a1eeb94-4ce9-7b79-aa1f-87d376e76b5c.png differ diff --git a/TP/TP01/P06/img/7d4ed9e8-6561-a816-39b3-fdb15edfb716.png b/TP/TP01/P06/img/7d4ed9e8-6561-a816-39b3-fdb15edfb716.png new file mode 100644 index 0000000000000000000000000000000000000000..8e91d6c8a3cc595b5a4639c8b80240652de1b7b7 Binary files /dev/null and b/TP/TP01/P06/img/7d4ed9e8-6561-a816-39b3-fdb15edfb716.png differ diff --git a/TP/TP01/P06/img/831240cd-35ec-6d3d-14a9-dfe09cf71828.png b/TP/TP01/P06/img/831240cd-35ec-6d3d-14a9-dfe09cf71828.png new file mode 100644 index 0000000000000000000000000000000000000000..820199db65d42cd9dade22e248149dd8852b8338 Binary files /dev/null and b/TP/TP01/P06/img/831240cd-35ec-6d3d-14a9-dfe09cf71828.png differ diff --git a/TP/TP01/P06/img/8446d790-b98c-3feb-a82e-457056e97ae7.png b/TP/TP01/P06/img/8446d790-b98c-3feb-a82e-457056e97ae7.png new file mode 100644 index 0000000000000000000000000000000000000000..eac0f21d9e3136700f3486e25cddecf0a5c3df0e Binary files /dev/null and b/TP/TP01/P06/img/8446d790-b98c-3feb-a82e-457056e97ae7.png differ diff --git a/TP/TP01/P06/img/88d7e60a-0e26-8bf4-c221-2e6769762253.png b/TP/TP01/P06/img/88d7e60a-0e26-8bf4-c221-2e6769762253.png new file mode 100644 index 0000000000000000000000000000000000000000..5ed53176cc4b88f04003cafaef6d5c1ef7d5e4ed Binary files /dev/null and b/TP/TP01/P06/img/88d7e60a-0e26-8bf4-c221-2e6769762253.png differ diff --git a/TP/TP01/P06/img/8e345aed-81be-c51b-678b-a64a5a106b65.png b/TP/TP01/P06/img/8e345aed-81be-c51b-678b-a64a5a106b65.png new file mode 100644 index 0000000000000000000000000000000000000000..bb57f494e33f867ad06ed9a29ad7d46da3160b80 Binary files /dev/null and b/TP/TP01/P06/img/8e345aed-81be-c51b-678b-a64a5a106b65.png differ diff --git a/TP/TP01/P06/img/8fc3bdb8-9794-002e-4e4f-c744c9573321.png b/TP/TP01/P06/img/8fc3bdb8-9794-002e-4e4f-c744c9573321.png new file mode 100644 index 0000000000000000000000000000000000000000..08f5b018eaa07c6eb048a901eab1205211b45dfb Binary files /dev/null and b/TP/TP01/P06/img/8fc3bdb8-9794-002e-4e4f-c744c9573321.png differ diff --git a/TP/TP01/P06/img/9bc4b9d8-0bc8-9842-65c2-708b6c282bbe.png b/TP/TP01/P06/img/9bc4b9d8-0bc8-9842-65c2-708b6c282bbe.png new file mode 100644 index 0000000000000000000000000000000000000000..90d7bf768f3dfbaa713d31f15455b4bf5c29e5a4 Binary files /dev/null and b/TP/TP01/P06/img/9bc4b9d8-0bc8-9842-65c2-708b6c282bbe.png differ diff --git a/TP/TP01/P06/img/a13c8786-beda-c3aa-6449-4ff54a82353f.png b/TP/TP01/P06/img/a13c8786-beda-c3aa-6449-4ff54a82353f.png new file mode 100644 index 0000000000000000000000000000000000000000..2bc14912b5abb76bffbdac845251de8cd6ffbd85 Binary files /dev/null and b/TP/TP01/P06/img/a13c8786-beda-c3aa-6449-4ff54a82353f.png differ diff --git a/TP/TP01/P06/img/a15d4d58-d871-6be4-2ce5-0c61ab7c9ae8.png b/TP/TP01/P06/img/a15d4d58-d871-6be4-2ce5-0c61ab7c9ae8.png new file mode 100644 index 0000000000000000000000000000000000000000..2fa32344d8253b70a1e844a17ed6f1765ed85a3b Binary files /dev/null and b/TP/TP01/P06/img/a15d4d58-d871-6be4-2ce5-0c61ab7c9ae8.png differ diff --git a/TP/TP01/P06/img/a3412540-2a35-9f51-5766-507c274f9c4e.png b/TP/TP01/P06/img/a3412540-2a35-9f51-5766-507c274f9c4e.png new file mode 100644 index 0000000000000000000000000000000000000000..6af60928ea78e14fa5bbf1ec2b31cd1bf01a8828 Binary files /dev/null and b/TP/TP01/P06/img/a3412540-2a35-9f51-5766-507c274f9c4e.png differ diff --git a/TP/TP01/P06/img/ac367b60-a112-3de1-c9c4-a6aa62ab4104.png b/TP/TP01/P06/img/ac367b60-a112-3de1-c9c4-a6aa62ab4104.png new file mode 100644 index 0000000000000000000000000000000000000000..90626f563b0d0ed7b221a31115cdcb43a68871d4 Binary files /dev/null and b/TP/TP01/P06/img/ac367b60-a112-3de1-c9c4-a6aa62ab4104.png differ diff --git a/TP/TP01/P06/img/b1b7f3d1-a8d1-00ae-d25d-e998d6bcfa1c.png b/TP/TP01/P06/img/b1b7f3d1-a8d1-00ae-d25d-e998d6bcfa1c.png new file mode 100644 index 0000000000000000000000000000000000000000..1ac4ab1b03184d5fad510acc6550541894ba34a5 Binary files /dev/null and b/TP/TP01/P06/img/b1b7f3d1-a8d1-00ae-d25d-e998d6bcfa1c.png differ diff --git a/TP/TP01/P06/img/b23dbd78-03f6-9546-8086-f7d03719892c.png b/TP/TP01/P06/img/b23dbd78-03f6-9546-8086-f7d03719892c.png new file mode 100644 index 0000000000000000000000000000000000000000..5ed53176cc4b88f04003cafaef6d5c1ef7d5e4ed Binary files /dev/null and b/TP/TP01/P06/img/b23dbd78-03f6-9546-8086-f7d03719892c.png differ diff --git a/TP/TP01/P06/img/b2bddae4-bdf1-37c1-a226-4058695bd7da.png b/TP/TP01/P06/img/b2bddae4-bdf1-37c1-a226-4058695bd7da.png new file mode 100644 index 0000000000000000000000000000000000000000..3cf9ddbdb2ffb5df88ad9818050459b04f60c5ff Binary files /dev/null and b/TP/TP01/P06/img/b2bddae4-bdf1-37c1-a226-4058695bd7da.png differ diff --git a/TP/TP01/P06/img/b9d6028a-bcab-ac9f-313e-484ef0e934de.png b/TP/TP01/P06/img/b9d6028a-bcab-ac9f-313e-484ef0e934de.png new file mode 100644 index 0000000000000000000000000000000000000000..aa20a6b98eb22e4f6161345966ad7db81fa99409 Binary files /dev/null and b/TP/TP01/P06/img/b9d6028a-bcab-ac9f-313e-484ef0e934de.png differ diff --git a/TP/TP01/P06/img/ba5b9967-b9d2-11c0-a118-74e1868f8b27.png b/TP/TP01/P06/img/ba5b9967-b9d2-11c0-a118-74e1868f8b27.png new file mode 100644 index 0000000000000000000000000000000000000000..ebde888a2d334e458997a08717b1936bdce6fca2 Binary files /dev/null and b/TP/TP01/P06/img/ba5b9967-b9d2-11c0-a118-74e1868f8b27.png differ diff --git a/TP/TP01/P06/img/bc45d770-bdca-7037-94e1-5ebc99a790df.png b/TP/TP01/P06/img/bc45d770-bdca-7037-94e1-5ebc99a790df.png new file mode 100644 index 0000000000000000000000000000000000000000..2edc0e8dfbd73510f7bb977f51977f6edf57c884 Binary files /dev/null and b/TP/TP01/P06/img/bc45d770-bdca-7037-94e1-5ebc99a790df.png differ diff --git a/TP/TP01/P06/img/bf35e754-3248-b1e0-2135-f1f932cc64b8.png b/TP/TP01/P06/img/bf35e754-3248-b1e0-2135-f1f932cc64b8.png new file mode 100644 index 0000000000000000000000000000000000000000..32eedfed498c1d916411ebd367585d33f2b33136 Binary files /dev/null and b/TP/TP01/P06/img/bf35e754-3248-b1e0-2135-f1f932cc64b8.png differ diff --git a/TP/TP01/P06/img/cursor-pause.png b/TP/TP01/P06/img/cursor-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9c93cc142f4326a188eafc3c0fe96f2975dcab0c Binary files /dev/null and b/TP/TP01/P06/img/cursor-pause.png differ diff --git a/TP/TP01/P06/img/cursor.png b/TP/TP01/P06/img/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..5b4a20e63078ce18bb11a4e601a1994b261522ef Binary files /dev/null and b/TP/TP01/P06/img/cursor.png differ diff --git a/TP/TP01/P06/img/d7949e73-b929-6a59-1897-4f72d87bacc1.png b/TP/TP01/P06/img/d7949e73-b929-6a59-1897-4f72d87bacc1.png new file mode 100644 index 0000000000000000000000000000000000000000..16808792a0cedf34e72c462172fb44797136bfe1 Binary files /dev/null and b/TP/TP01/P06/img/d7949e73-b929-6a59-1897-4f72d87bacc1.png differ diff --git a/TP/TP01/P06/img/dea2d804-30cd-960c-f463-85d43ed71728.png b/TP/TP01/P06/img/dea2d804-30cd-960c-f463-85d43ed71728.png new file mode 100644 index 0000000000000000000000000000000000000000..20399f39e7a77b1f57814b86341f1449448b73d4 Binary files /dev/null and b/TP/TP01/P06/img/dea2d804-30cd-960c-f463-85d43ed71728.png differ diff --git a/TP/TP01/P06/img/e334e4c2-8999-1d11-f12c-3f0c78205e18.png b/TP/TP01/P06/img/e334e4c2-8999-1d11-f12c-3f0c78205e18.png new file mode 100644 index 0000000000000000000000000000000000000000..820199db65d42cd9dade22e248149dd8852b8338 Binary files /dev/null and b/TP/TP01/P06/img/e334e4c2-8999-1d11-f12c-3f0c78205e18.png differ diff --git a/TP/TP01/P06/img/ef2ad1aa-8dd4-0fbb-e149-0bf3fa50128f.png b/TP/TP01/P06/img/ef2ad1aa-8dd4-0fbb-e149-0bf3fa50128f.png new file mode 100644 index 0000000000000000000000000000000000000000..bf25c32570e934f0dc50bd2201f68e424b2840e9 Binary files /dev/null and b/TP/TP01/P06/img/ef2ad1aa-8dd4-0fbb-e149-0bf3fa50128f.png differ diff --git a/TP/TP01/P06/img/f170cb4d-cbc5-9b97-65e3-f88a4518fa8e.png b/TP/TP01/P06/img/f170cb4d-cbc5-9b97-65e3-f88a4518fa8e.png new file mode 100644 index 0000000000000000000000000000000000000000..25a4b4675ca9d7ad57ac1e6d6ff2b856a03f25b1 Binary files /dev/null and b/TP/TP01/P06/img/f170cb4d-cbc5-9b97-65e3-f88a4518fa8e.png differ diff --git a/TP/TP01/P06/img/f79f8a7d-895d-32f8-126c-288b8e56cdd5.png b/TP/TP01/P06/img/f79f8a7d-895d-32f8-126c-288b8e56cdd5.png new file mode 100644 index 0000000000000000000000000000000000000000..e2b84f4146f689d4d7cdd5f8eed64974e6851ee0 Binary files /dev/null and b/TP/TP01/P06/img/f79f8a7d-895d-32f8-126c-288b8e56cdd5.png differ diff --git a/TP/TP01/P06/img/fe0f12ec-4234-8b06-3daf-e42e03d5726d.png b/TP/TP01/P06/img/fe0f12ec-4234-8b06-3daf-e42e03d5726d.png new file mode 100644 index 0000000000000000000000000000000000000000..2b6cf000ede95a69011accc5bf7ca4e71b040648 Binary files /dev/null and b/TP/TP01/P06/img/fe0f12ec-4234-8b06-3daf-e42e03d5726d.png differ diff --git a/TP/TP01/P06/index.html b/TP/TP01/P06/index.html new file mode 100644 index 0000000000000000000000000000000000000000..d202e7594e68ea47b785981a166f667bfd19bb6a --- /dev/null +++ b/TP/TP01/P06/index.html @@ -0,0 +1,817 @@ +<!DOCTYPE html> + +<html lang="en"> + +<head> +<title>Dahu Presentation +</title> +<meta charset="utf-8"> +<script src="http://code.jquery.com/jquery-1.9.1.min.js" type="text/javascript"> +</script> +<script src="parse-search.js" type="text/javascript"> +</script> + +<link rel="stylesheet" href="dahuapp.viewer.css"><style>.s0-o2{background-color: #FFFFDD;width: 240px} +.s2-o2{background-color: #FFFFDD;width: 240px} +.s3-o2{background-color: #FFFFDD;width: 240px} +.s4-o2{background-color: #FFFFDD;width: 240px} +.s5-o2{background-color: #FFFFDD;width: 240px} +.s6-o2{background-color: #FFFFDD;width: 240px} +.s7-o2{background-color: #FFFFDD;width: 240px} +.s8-o2{background-color: #FFFFDD;width: 240px} +.s9-o2{background-color: #FFFFDD;width: 240px} +.s11-o2{background-color: #FFFFDD;width: 240px} +.s12-o2{background-color: #FFFFDD;width: 240px} +.s13-o2{background-color: #FFFFDD;width: 240px} +.s15-o2{background-color: #FFFFDD;width: 240px} +.s15-o2{background-color: #FFFFDD;width: 240px} +.s16-o2{background-color: #FFFFDD;width: 240px} +.s17-o2{background-color: #FFFFDD;width: 240px} +.s18-o2{background-color: #FFFFDD;width: 240px} +.s19-o2{background-color: #FFFFDD;width: 240px} +.s20-o2{background-color: #FFFFDD;width: 240px} +.s21-o2{background-color: #FFFFDD;width: 240px} +.s22-o2{background-color: #FFFFDD;width: 240px} +.s23-o2{background-color: #FFFFDD;width: 240px} +.s38-o2{background-color: #FFFFDD;width: 240px} +</style> +</head> + +<body> + +<div id="my-dahu-presentation"> + +<div id="loading">Loading presentation... +</div> + +<div class="object-list" style="display: none"> +<img src="img/d7949e73-b929-6a59-1897-4f72d87bacc1.png" alt="img/d7949e73-b929-6a59-1897-4f72d87bacc1.png" class="background d7949e73-b929-6a59-1897-4f72d87bacc10"> + +<div class="tooltip s0-o2">Créer un nouveau modèle Simulink. +</div> +<img src="img/a3412540-2a35-9f51-5766-507c274f9c4e.png" alt="img/a3412540-2a35-9f51-5766-507c274f9c4e.png" class="background a3412540-2a35-9f51-5766-507c274f9c4e0"> +<img src="img/b1b7f3d1-a8d1-00ae-d25d-e998d6bcfa1c.png" alt="img/b1b7f3d1-a8d1-00ae-d25d-e998d6bcfa1c.png" class="background b1b7f3d1-a8d1-00ae-d25d-e998d6bcfa1c0"> + +<div class="tooltip s2-o2">Sélectionner le bloc Constante dans la boite à outils Simulink. +</div> +<img src="img/636bdb73-2612-3933-1f1b-6022d6e33625.png" alt="img/636bdb73-2612-3933-1f1b-6022d6e33625.png" class="background 636bdb73-2612-3933-1f1b-6022d6e336250"> + +<div class="tooltip s3-o2">Déposer un bloc Constante pour la gravité g. +</div> +<img src="img/b2bddae4-bdf1-37c1-a226-4058695bd7da.png" alt="img/b2bddae4-bdf1-37c1-a226-4058695bd7da.png" class="background b2bddae4-bdf1-37c1-a226-4058695bd7da0"> + +<div class="tooltip s4-o2">Choisir la valeur [ 0 -9.81 ] pour le bloc Constante. Il s'agit d'un vecteur composée de l'horizontale et la verticale. +</div> +<img src="img/44cbf940-d047-a39e-6fee-2d91ef83f91c.png" alt="img/44cbf940-d047-a39e-6fee-2d91ef83f91c.png" class="background 44cbf940-d047-a39e-6fee-2d91ef83f91c0"> + +<div class="tooltip s5-o2">Sélectionner le bloc Integrator. +</div> +<img src="img/2ab20dfd-b528-4e65-28d0-5bbe0ce71d26.png" alt="img/2ab20dfd-b528-4e65-28d0-5bbe0ce71d26.png" class="background 2ab20dfd-b528-4e65-28d0-5bbe0ce71d260"> + +<div class="tooltip s6-o2">Positionner un bloc Integrator pour calculer la vitesse à partir de l'accéleration. +</div> +<img src="img/bf35e754-3248-b1e0-2135-f1f932cc64b8.png" alt="img/bf35e754-3248-b1e0-2135-f1f932cc64b8.png" class="background bf35e754-3248-b1e0-2135-f1f932cc64b80"> + +<div class="tooltip s7-o2">Positionner un bloc Integrator pour calculer la position du mobile à partir de la vitesse. +</div> +<img src="img/37c23d3f-b713-19c2-ff10-7e177eb69c38.png" alt="img/37c23d3f-b713-19c2-ff10-7e177eb69c38.png" class="background 37c23d3f-b713-19c2-ff10-7e177eb69c380"> + +<div class="tooltip s8-o2">Configurer le bloc Integrator pour fournir la valeur initiale depuis un port externe. +</div> +<img src="img/f79f8a7d-895d-32f8-126c-288b8e56cdd5.png" alt="img/f79f8a7d-895d-32f8-126c-288b8e56cdd5.png" class="background f79f8a7d-895d-32f8-126c-288b8e56cdd50"> + +<div class="tooltip s9-o2">Configurer le bloc Integrator pour fournir la valeur initiale depuis un port externe. +</div> +<img src="img/4daad903-6dbe-5e6c-cc1b-12ad9749eb53.png" alt="img/4daad903-6dbe-5e6c-cc1b-12ad9749eb53.png" class="background 4daad903-6dbe-5e6c-cc1b-12ad9749eb530"> +<img src="img/8e345aed-81be-c51b-678b-a64a5a106b65.png" alt="img/8e345aed-81be-c51b-678b-a64a5a106b65.png" class="background 8e345aed-81be-c51b-678b-a64a5a106b650"> + +<div class="tooltip s11-o2">Déposer deux blocs Constante pour les valeurs initiales de la vitesse et de la position. +</div> +<img src="img/05133e21-8ad0-1342-3568-c459d579b14a.png" alt="img/05133e21-8ad0-1342-3568-c459d579b14a.png" class="background 05133e21-8ad0-1342-3568-c459d579b14a0"> + +<div class="tooltip s12-o2">Nommer les blocs Constant G, V0 et P0. +</div> +<img src="img/f170cb4d-cbc5-9b97-65e3-f88a4518fa8e.png" alt="img/f170cb4d-cbc5-9b97-65e3-f88a4518fa8e.png" class="background f170cb4d-cbc5-9b97-65e3-f88a4518fa8e0"> + +<div class="tooltip s13-o2">Choisir la valeur [ 10 10 ] pour le bloc Constante correspondant à la vitesse initiale. Il s'agit d'un vecteur composée de l'horizontale et la verticale. +</div> +<img src="img/30445c44-4357-cb29-da5c-dd8a9418ce31.png" alt="img/30445c44-4357-cb29-da5c-dd8a9418ce31.png" class="background 30445c44-4357-cb29-da5c-dd8a9418ce310"> + +<div class="tooltip s15-o2">Choisir la valeur [ 0 20 ] pour le bloc Constante correspondant à la position initiale. Il s'agit d'un vecteur composée de l'horizontale et la verticale. +</div> +<img src="img/9bc4b9d8-0bc8-9842-65c2-708b6c282bbe.png" alt="img/9bc4b9d8-0bc8-9842-65c2-708b6c282bbe.png" class="background 9bc4b9d8-0bc8-9842-65c2-708b6c282bbe0"> + +<div class="tooltip s15-o2">Connecter les ports d'entrée et de sortie des différents blocs. +</div> +<img src="img/24ac7258-308f-3469-7ff3-73cd1714356b.png" alt="img/24ac7258-308f-3469-7ff3-73cd1714356b.png" class="background 24ac7258-308f-3469-7ff3-73cd1714356b0"> + +<div class="tooltip s16-o2">Déposer un bloc Oscilloscope. +</div> +<img src="img/28cc4893-5425-5aac-05e8-a7e32ca109b8.png" alt="img/28cc4893-5425-5aac-05e8-a7e32ca109b8.png" class="background 28cc4893-5425-5aac-05e8-a7e32ca109b80"> + +<div class="tooltip s17-o2">Connecter les ports d'entrée et de sortie. +</div> +<img src="img/571c8ded-4b8d-dfed-d850-b84ae3ec961e.png" alt="img/571c8ded-4b8d-dfed-d850-b84ae3ec961e.png" class="background 571c8ded-4b8d-dfed-d850-b84ae3ec961e0"> + +<div class="tooltip s18-o2">Démarrer la simulation. L'écran de l'oscilloscope affiche les deux valeurs du vecteur (position horizontale en jaune et verticale en violet). +</div> +<img src="img/146e7fd1-79a9-d471-f996-f583ba0fe8f9.png" alt="img/146e7fd1-79a9-d471-f996-f583ba0fe8f9.png" class="background 146e7fd1-79a9-d471-f996-f583ba0fe8f90"> + +<div class="tooltip s19-o2">Déposer un bloc Oscilloscope X-Y (afficheur 2 dimensions). +</div> +<img src="img/8446d790-b98c-3feb-a82e-457056e97ae7.png" alt="img/8446d790-b98c-3feb-a82e-457056e97ae7.png" class="background 8446d790-b98c-3feb-a82e-457056e97ae70"> + +<div class="tooltip s20-o2">Déposer un bloc Demux qui sépare le vecteur en 2 scalaires. +</div> +<img src="img/042b3794-32ee-9789-5a5e-7492c70ea14b.png" alt="img/042b3794-32ee-9789-5a5e-7492c70ea14b.png" class="background 042b3794-32ee-9789-5a5e-7492c70ea14b0"> + +<div class="tooltip s21-o2">Connecter les deux composantes du vecteur sur les deux entrées du bloc Oscilloscope X-Y. +</div> +<img src="img/a13c8786-beda-c3aa-6449-4ff54a82353f.png" alt="img/a13c8786-beda-c3aa-6449-4ff54a82353f.png" class="background a13c8786-beda-c3aa-6449-4ff54a82353f0"> + +<div class="tooltip s22-o2">Configurer le bloc Oscilloscope X-Y avec le domaine [ 0 100 ] pour l'abscisse et [ -400 50 ] pour l'ordonnée. +</div> +<img src="img/b9d6028a-bcab-ac9f-313e-484ef0e934de.png" alt="img/b9d6028a-bcab-ac9f-313e-484ef0e934de.png" class="background b9d6028a-bcab-ac9f-313e-484ef0e934de0"> + +<div class="tooltip s23-o2">Démarrer la simulation. +</div> +<img src="img/ac367b60-a112-3de1-c9c4-a6aa62ab4104.png" alt="img/ac367b60-a112-3de1-c9c4-a6aa62ab4104.png" class="background ac367b60-a112-3de1-c9c4-a6aa62ab41040"> + +<div class="tooltip s38-o2">Donner un nom à tous les signaux. +</div> + +<div class="mouse-cursor"> +<img src="img/cursor.png" alt="img/cursor.png" class="mouse-cursor-normal"> +<img src="img/cursor-pause.png" alt="img/cursor-pause.png" style="display: none" class="mouse-cursor-pause"> +</div> +</div> + +<div class="control" style="top: 616px;"> +<button class="previous">Previous +</button> +<button class="next">Next +</button> +</div> +</div> +<script src="dahuapp.js" type="text/javascript"> +</script> +<script src="dahuapp.viewer.js" type="text/javascript"> +</script> +<script type="text/javascript">(function($) { + var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams); + myPresentation.load({ + "metaData": { + "imageWidth": 800, + "imageHeight": 600, + "initialBackgroundId": "d7949e73-b929-6a59-1897-4f72d87bacc10", + "initialMouseX": 0.20416666666666666, + "initialMouseY": 0.08555555555555555 + }, + "action": [ + { + "id": "87", + "type": "appear", + "target": "s0-o2", + "trigger": "afterPrevious", + "abs": 0.20166666666666666, + "ord": 0.0825, + "duration": 400 + }, + { + "id": "3", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.1125, + "finalOrd": 0.29, + "speed": 0.8 + }, + { + "id": "4", + "type": "appear", + "target": "a3412540-2a35-9f51-5766-507c274f9c4e0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "5", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.8958333333333334, + "finalOrd": 0.2222222222222222, + "speed": 0.8 + }, + { + "id": "6", + "type": "appear", + "target": "b1b7f3d1-a8d1-00ae-d25d-e998d6bcfa1c0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "88", + "type": "appear", + "target": "s2-o2", + "trigger": "afterPrevious", + "abs": 0.4066666666666667, + "ord": 0.11875, + "duration": 400 + }, + { + "id": "7", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.18472222222222223, + "finalOrd": 0.2511111111111111, + "speed": 0.8 + }, + { + "id": "8", + "type": "appear", + "target": "636bdb73-2612-3933-1f1b-6022d6e336250", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "89", + "type": "appear", + "target": "s3-o2", + "trigger": "afterPrevious", + "abs": 0.25, + "ord": 0.1775, + "duration": 400 + }, + { + "id": "9", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.26319444444444445, + "finalOrd": 0.23777777777777778, + "speed": 0.8 + }, + { + "id": "10", + "type": "appear", + "target": "b2bddae4-bdf1-37c1-a226-4058695bd7da0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "90", + "type": "appear", + "target": "s4-o2", + "trigger": "afterPrevious", + "abs": 0.22166666666666668, + "ord": 0.265, + "duration": 400 + }, + { + "id": "11", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.9034722222222222, + "finalOrd": 0.1688888888888889, + "speed": 0.8 + }, + { + "id": "12", + "type": "appear", + "target": "44cbf940-d047-a39e-6fee-2d91ef83f91c0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "91", + "type": "appear", + "target": "s5-o2", + "trigger": "afterPrevious", + "abs": 0.7916666666666666, + "ord": 0.1275, + "duration": 400 + }, + { + "id": "13", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2902777777777778, + "finalOrd": 0.2577777777777778, + "speed": 0.8 + }, + { + "id": "14", + "type": "appear", + "target": "2ab20dfd-b528-4e65-28d0-5bbe0ce71d260", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "92", + "type": "appear", + "target": "s6-o2", + "trigger": "afterPrevious", + "abs": 0.21333333333333335, + "ord": 0.18875, + "duration": 400 + }, + { + "id": "15", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3875, + "finalOrd": 0.26555555555555554, + "speed": 0.8 + }, + { + "id": "16", + "type": "appear", + "target": "bf35e754-3248-b1e0-2135-f1f932cc64b80", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "93", + "type": "appear", + "target": "s7-o2", + "trigger": "afterPrevious", + "abs": 0.23, + "ord": 0.20625, + "duration": 400 + }, + { + "id": "17", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.4027777777777778, + "finalOrd": 0.19666666666666666, + "speed": 0.8 + }, + { + "id": "18", + "type": "appear", + "target": "37c23d3f-b713-19c2-ff10-7e177eb69c380", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "94", + "type": "appear", + "target": "s8-o2", + "trigger": "afterPrevious", + "abs": 0.23833333333333334, + "ord": 0.18875, + "duration": 400 + }, + { + "id": "19", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.50625, + "finalOrd": 0.19777777777777777, + "speed": 0.8 + }, + { + "id": "20", + "type": "appear", + "target": "f79f8a7d-895d-32f8-126c-288b8e56cdd50", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "95", + "type": "appear", + "target": "s9-o2", + "trigger": "afterPrevious", + "abs": 0.39666666666666667, + "ord": 0.15875, + "duration": 400 + }, + { + "id": "21", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.8916666666666667, + "finalOrd": 0.21888888888888888, + "speed": 0.8 + }, + { + "id": "22", + "type": "appear", + "target": "4daad903-6dbe-5e6c-cc1b-12ad9749eb530", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "23", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.18333333333333332, + "finalOrd": 0.45555555555555555, + "speed": 0.8 + }, + { + "id": "24", + "type": "appear", + "target": "8e345aed-81be-c51b-678b-a64a5a106b650", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "96", + "type": "appear", + "target": "s11-o2", + "trigger": "afterPrevious", + "abs": 0.28833333333333333, + "ord": 0.20875, + "duration": 400 + }, + { + "id": "29", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.18819444444444444, + "finalOrd": 0.4811111111111111, + "speed": 0.8 + }, + { + "id": "30", + "type": "appear", + "target": "05133e21-8ad0-1342-3568-c459d579b14a0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "97", + "type": "appear", + "target": "s12-o2", + "trigger": "afterPrevious", + "abs": 0.275, + "ord": 0.21, + "duration": 400 + }, + { + "id": "31", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.25416666666666665, + "finalOrd": 0.3477777777777778, + "speed": 0.8 + }, + { + "id": "32", + "type": "appear", + "target": "f170cb4d-cbc5-9b97-65e3-f88a4518fa8e0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "98", + "type": "appear", + "target": "s13-o2", + "trigger": "afterPrevious", + "abs": 0.16333333333333333, + "ord": 0.3575, + "duration": 400 + }, + { + "id": "35", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2590277777777778, + "finalOrd": 0.42777777777777776, + "speed": 0.8 + }, + { + "id": "36", + "type": "appear", + "target": "30445c44-4357-cb29-da5c-dd8a9418ce310", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "99", + "type": "appear", + "target": "s15-o2", + "trigger": "afterPrevious", + "abs": 0.12833333333333333, + "ord": 0.37625, + "duration": 400 + }, + { + "id": "37", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3680555555555556, + "finalOrd": 0.31, + "speed": 0.8 + }, + { + "id": "38", + "type": "appear", + "target": "9bc4b9d8-0bc8-9842-65c2-708b6c282bbe0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "100", + "type": "appear", + "target": "s15-o2", + "trigger": "afterPrevious", + "abs": 0.25, + "ord": 0.27125, + "duration": 400 + }, + { + "id": "41", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.5083333333333333, + "finalOrd": 0.2722222222222222, + "speed": 0.8 + }, + { + "id": "42", + "type": "appear", + "target": "24ac7258-308f-3469-7ff3-73cd1714356b0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "101", + "type": "appear", + "target": "s16-o2", + "trigger": "afterPrevious", + "abs": 0.485, + "ord": 0.19375, + "duration": 400 + }, + { + "id": "43", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.4979166666666667, + "finalOrd": 0.27444444444444444, + "speed": 0.8 + }, + { + "id": "44", + "type": "appear", + "target": "28cc4893-5425-5aac-05e8-a7e32ca109b80", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "102", + "type": "appear", + "target": "s17-o2", + "trigger": "afterPrevious", + "abs": 0.44666666666666666, + "ord": 0.19375, + "duration": 400 + }, + { + "id": "45", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2902777777777778, + "finalOrd": 0.1, + "speed": 0.8 + }, + { + "id": "46", + "type": "appear", + "target": "571c8ded-4b8d-dfed-d850-b84ae3ec961e0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "103", + "type": "appear", + "target": "s18-o2", + "trigger": "afterPrevious", + "abs": 0.31833333333333336, + "ord": 0.4075, + "duration": 400 + }, + { + "id": "47", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.5069444444444444, + "finalOrd": 0.3933333333333333, + "speed": 0.8 + }, + { + "id": "48", + "type": "appear", + "target": "146e7fd1-79a9-d471-f996-f583ba0fe8f90", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "104", + "type": "appear", + "target": "s19-o2", + "trigger": "afterPrevious", + "abs": 0.455, + "ord": 0.2575, + "duration": 400 + }, + { + "id": "49", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.4375, + "finalOrd": 0.3611111111111111, + "speed": 0.8 + }, + { + "id": "50", + "type": "appear", + "target": "8446d790-b98c-3feb-a82e-457056e97ae70", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "105", + "type": "appear", + "target": "s20-o2", + "trigger": "afterPrevious", + "abs": 0.365, + "ord": 0.255, + "duration": 400 + }, + { + "id": "51", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.45694444444444443, + "finalOrd": 0.44666666666666666, + "speed": 0.8 + }, + { + "id": "52", + "type": "appear", + "target": "042b3794-32ee-9789-5a5e-7492c70ea14b0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "106", + "type": "appear", + "target": "s21-o2", + "trigger": "afterPrevious", + "abs": 0.3016666666666667, + "ord": 0.2825, + "duration": 400 + }, + { + "id": "53", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.5770833333333333, + "finalOrd": 0.5411111111111111, + "speed": 0.8 + }, + { + "id": "54", + "type": "appear", + "target": "a13c8786-beda-c3aa-6449-4ff54a82353f0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "107", + "type": "appear", + "target": "s22-o2", + "trigger": "afterPrevious", + "abs": 0.58, + "ord": 0.38125, + "duration": 400 + }, + { + "id": "55", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2875, + "finalOrd": 0.1, + "speed": 0.8 + }, + { + "id": "56", + "type": "appear", + "target": "b9d6028a-bcab-ac9f-313e-484ef0e934de0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "108", + "type": "appear", + "target": "s23-o2", + "trigger": "afterPrevious", + "abs": 0.16166666666666665, + "ord": 0.2875, + "duration": 400 + }, + { + "id": "85", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2965277777777778, + "finalOrd": 0.49666666666666665, + "speed": 0.8 + }, + { + "id": "86", + "type": "appear", + "target": "ac367b60-a112-3de1-c9c4-a6aa62ab41040", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "109", + "type": "appear", + "target": "s38-o2", + "trigger": "afterPrevious", + "abs": 0.27, + "ord": 0.2875, + "duration": 400 + } + ] +}); + myPresentation.start(); +})(jQuery); + +</script> +</body> +</html> \ No newline at end of file diff --git a/TP/TP01/P06/parse-search.js b/TP/TP01/P06/parse-search.js new file mode 100644 index 0000000000000000000000000000000000000000..e7d01c07f6a5d45b9fcabd5d271a8c6cfc5f00e2 --- /dev/null +++ b/TP/TP01/P06/parse-search.js @@ -0,0 +1,14 @@ +// Adapted from http://stackoverflow.com/questions/3234125/creating-array-from-window-location-hash +(function () { + var search = window.location.search.slice(1); + var array = search.split("&"); + + var values, form_data = {}; + + for (var i = 0; i < array.length; i += 1) { + values = array[i].split("="); + form_data[values[0]] = unescape(values[1]); + } + window.getParams = form_data; +}()) + diff --git a/TP/TP01/P07/dahuapp.js b/TP/TP01/P07/dahuapp.js new file mode 100644 index 0000000000000000000000000000000000000000..41c69e9169345a9a6703325d5557a4cc36913e19 --- /dev/null +++ b/TP/TP01/P07/dahuapp.js @@ -0,0 +1,880 @@ +"use strict"; + +/** + * Dahuapp core module. + * + * @param window window javascript object. + * @param $ jQuery + * @returns dahuapp core module. + */ +(function (window, $) { + var dahuapp = (function () { + + var self = {}; + + /* private API */ + + var DahuScreencastGenerator = function () { + + /* + * Format the specified string in a readable format. + */ + function htmlFormat(htmlString) { + var i; + var readableHTML = htmlString; + var lb = '\n'; + var htags = ["<html", "</html>", "</head>", "<title", "</title>", "<meta", "<link", "</body>"]; + for (i = 0; i < htags.length; ++i) { + var hhh = htags[i]; + readableHTML = readableHTML.replace(new RegExp(hhh, 'gi'), lb + hhh); + } + var btags = ["</div>", "</section>", "</span>", "<br>", "<br />", "<blockquote", "</blockquote>", "<ul", "</ul>", "<ol", "</ol>", "<li", "<\!--", "<script", "</script>"]; + for (i = 0; i < btags.length; ++i) { + var bbb = btags[i]; + readableHTML = readableHTML.replace(new RegExp(bbb, 'gi'), lb + bbb); + } + var ftags = ["<img", "<legend", "</legend>", "<button", "</button>"]; + for (i = 0; i < ftags.length; ++i) { + var fff = ftags[i]; + readableHTML = readableHTML.replace(new RegExp(fff, 'gi'), lb + fff); + } + var xtags = ["<body", "<head", "<div", "<section", "<span", "<p"]; + for (i = 0; i < xtags.length; ++i) { + var xxx = xtags[i]; + readableHTML = readableHTML.replace(new RegExp(xxx, 'gi'), lb + lb + xxx); + } + return readableHTML; + } + + /* + * Generates the html header. + */ + var generateHtmlHeader = function ($generated, cssGen) { + $('head', $generated) + .append($(document.createElement('title')) + .append("Dahu Presentation"))/* TODO: make this customizable */ + .append($(document.createElement('meta')) + .attr({'charset': 'utf-8'})) + .append($(document.createElement('script')) + .attr({'src': 'http://code.jquery.com/jquery-1.9.1.min.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'parse-search.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('link')) + .attr({'rel': 'stylesheet', 'href': 'dahuapp.viewer.css'})) + .append($(document.createElement('style')) + .append(cssGen)); + }; + + /* + * Generates the objects. + */ + + var generateHtmlBackgroundImage = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('img')) + .attr({'src': object.img, 'alt': object.img, 'class': 'background ' + object.id})); + }; + var generateHtmlTooltip = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'tooltip ' + object.id}) + .append(object.text)); + }; + + var generateCssTooltip = function ($generated, object) { + var style = []; + + if( object.color != null ) { + style.push('background-color: ' + object.color); + } + if( object.width != null ) { + style.push('width: ' + object.width); + } + + if( style.length != 0 ) { + $generated.append( + '.' + object.id + '{' + style.join(';') + '}\n'); + } + + return $generated; + }; + + /* + * Returns the code used to call the viewer to the presentation. + */ + var getBasicCallCode = function (jsonModel) { + var code = '(function($) {\n'; + code += ' var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams);\n'; + code += ' myPresentation.load(' + jsonModel + ');\n'; + code += ' myPresentation.start();\n'; + code += '})(jQuery);\n'; + return code; + }; + + /* + * Generates the html body. + */ + var generateHtmlBody = function ($generated, jsonModel, jsonGen) { + $('body', $generated) + /* We could use a <section> here too, but it does not work with MS IE 8. + Alternatively, adding this in the header would work: + + <!--[if lt IE 9]> + <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + */ + .append($(document.createElement('div')) + .attr({'id': 'my-dahu-presentation'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.viewer.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'type': 'text/javascript'}) + .append(getBasicCallCode(jsonGen))); + $('#my-dahu-presentation', $generated) + .append($(document.createElement('div')) + .attr({'id': 'loading'}).append("Loading presentation...")) + .append($(document.createElement('div')) + .attr({'class': 'object-list', + 'style': 'display: none'})) + .append($(document.createElement('div')) + .attr({'class': 'control'})); + + /* Adding the objects to the page */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "background": + generateHtmlBackgroundImage($generated, object); + break; + case "tooltip": + generateHtmlTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + /* Warning here, i'm not sure if $.each is always over, here */ + + /* Adding the control buttons to the page */ + $('.control', $generated) + .css({'top': (jsonModel.getImageHeight() + 16) + 'px'}) + .append($(document.createElement('button')) + .attr({'class': 'previous'}) + .append('Previous')) + .append($(document.createElement('button')) + .attr({'class': 'next'}) + .append('Next')); + + /* Adding the mouse cursor image */ + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'mouse-cursor'}) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor.png', 'alt': 'img/cursor.png', 'class': 'mouse-cursor-normal'})) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor-pause.png', 'alt': 'img/cursor-pause.png', + 'style': 'display: none', 'class': 'mouse-cursor-pause'}))); + }; + + /* + * Generates the css String with the Json model. + */ + this.generateCssString = function (jsonModel) { + var $generated = $('<style></style>'); + + /* Going through each object */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "tooltip": + generateCssTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + return $generated.text(); + } + + /* + * Generates the html String with the Json model. + */ + this.generateHtmlString = function (jsonModel, jsonGen, cssGen) { + /* Initialising the compilation area */ + var $generated = $(document.createElement('div')); + + /* We create the html using the json */ + $generated.append($(document.createElement('html')) + .attr({'lang': 'en'})); + $('html', $generated) + .append($(document.createElement('head'))) + .append($(document.createElement('body'))); + + generateHtmlHeader($generated, cssGen); + generateHtmlBody($generated, jsonModel, jsonGen); + + var result = htmlFormat($generated.html()); + + return '<!DOCTYPE html>\n' + result; + }; + + /* + * Generates the generated JSON using the JSONmodel. + * @param {object} jsonModel The json model to transform. + * @param {java.awt.Dimension} imgDim The dimension of images. + */ + this.generateJsonString = function (jsonModel, imgDim) { + var generated = self.createScreencastGeneratedModel(); + generated.setImageSize(imgDim.width, imgDim.height); + generated.setInitialBackground(jsonModel.getInitialBackground()); + generated.setInitialMousePos(jsonModel.getInitialMousePos()); + for (var i = 0; i < jsonModel.getNbSlide(); i++) { + var actionList = jsonModel.getActionList(i); + for (var j = 0; j < actionList.length; j++) { + /* + * We don't add the two first actions of the first slide + * because they are present in the presentation metadata. + * It corresponds to the mouse initial pos and first background. + */ + if (i > 0 || j > 1) { + generated.addAction(actionList[j], imgDim.width, imgDim.height); + } + } + } + return generated.getJson(); + }; + }; + + /* + * Model for a JSON object that will only be used by the viewer, never + * saved on a file, used to transform the properties of actions + * specified on the JSON file of a presentation to executable + * functions for each action. + */ + var DahuScreencastExecutableModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* + * Creates a functions representing the specified action, and adds + * it to this object. + * @param {object} action + */ + var addExecutableAction = function (action) { + var executableAction = { + 'id': action.id, + 'trigger': action.trigger, + 'target': action.target, + 'delayAfter': action.delayAfter, + 'doneFunction': function (events, selector) { + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.delayAfter); + } + }; + if (executableAction.delayAfter == null) { + executableAction.delayAfter = 200; + } + switch (action.type.toLowerCase()) { + case "appear": + executableAction.abs = (action.abs * json.metaData.imageWidth) + 'px'; + executableAction.ord = (action.ord * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(); + }; + break; + case "disappear": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + $(selector + ' .' + this.target).hide(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).show(); + }; + executableAction.executeImmediately = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + break; + case "move": + executableAction.finalAbs = (action.finalAbs * json.metaData.imageWidth) + 'px'; + executableAction.finalOrd = (action.finalOrd * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.speed = action.speed; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + if (this.duration == null) { + var initialAbsPix = this.initialAbs.replace('px', ''); + var initialOrdPix = this.initialOrd.replace('px', ''); + var finalAbsPix = this.finalAbs.replace('px', ''); + var finalOrdPix = this.finalOrd.replace('px', ''); + var distance = Math.sqrt(Math.pow(finalAbsPix - initialAbsPix, 2) + + Math.pow(finalOrdPix - initialOrdPix, 2)); + if (!this.speed) { + this.speed = .8; // in pixel per milisecond: fast, but not too much. + } + this.duration = distance + this.speed; + if (this.duration < 200) { // Slow down a bit for short distances. + this.duration = 200; + } + } + $(sel).animate({ + 'left': this.finalAbs, + 'top': this.finalOrd + }, this.duration, 'linear', function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).css({ + 'left': this.initialAbs, + 'top': this.initialOrd + }); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + $(sel).css({ + 'left': this.finalAbs, + 'top': this.finalOrd + }); + }; + break; + case "delay": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.duration); + }; + executableAction.executeReverse = function (selector) { + // Nothing! + }; + executableAction.executeImmediately = function (selector) { + // Nothing too! + }; + break; + } + json.action.push(executableAction); + }; + + /* Public API */ + + /* + * Loads the specified JSON read from a 'presentation.json' file, + * and stores the functions representing each actions in an object. + * @param {object} jsonToLoad + */ + this.loadJson = function (jsonToLoad) { + json.metaData = jsonToLoad.metaData; + for (var i = 0; i < jsonToLoad.action.length; i++) { + addExecutableAction(jsonToLoad.action[i]); + } + }; + + /* + * Returns the object containing the functions. + */ + this.getJson = function () { + return json; + }; + }; + + /* + * Used to transform the 'dahu' file to a JSON file used by the viewer, + * which only contains some metaData and a list of actions. + */ + var DahuScreencastGeneratedModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* Public API */ + + /* + * Returns a string representation of this json. + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * Setters for the generated json metadata. + */ + this.setImageSize = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + this.setInitialMousePos = function (pos) { + json.metaData.initialMouseX = pos.x; + json.metaData.initialMouseY = pos.y; + }; + + this.setInitialBackground = function (id) { + json.metaData.initialBackgroundId = id; + }; + + this.addAction = function (action) { + json.action.push(action); + }; + + /* + * Transforms a JSON containing action properties to a JSON containing + * the execution functions. + * @param {Object} json + * @returns {Object} A json object containing the execution functions + * for all the actions of the presentation. + */ + this.toExecutableList = function (json) { + var executableList = { + metaData: json.metaData, + action: new Array() + }; + for (var i = 0; i < json.action.length; i++) { + addExecutableAction(executableList, json.action[i]); + } + return executableList; + }; + }; + + /* + * Represents a 'dahu' file for a project. + */ + var DahuScreencastModel = function () { + + /* Private API */ + + var json = {}; + + /* + * Generates a unique action ID. + * + * With this implementation, this ID is unique as long as the user + * doesn't replace it manually with a not kind value or replace + * the nextUniqueId with bad intentions. + * But maybe that a UUID is a bit tiresome to put as an anchor... + */ + var generateUniqueActionId = function () { + json.metaData.nextUniqueId++; + return json.metaData.nextUniqueId.toString(); + }; + + /* + * This method checks if the json representing a dahu project is + * in the good version. It's in case a project file was created + * with a previous version of Dahu, and that some fields are + * missing. + * + * It doesn't control each field (at the moment) but only the + * fields that can be missing due to a new Dahu version and not + * to a manual editing. + * + * This method doesn't check any Json syntax or something like that. + */ + var upgradeJsonVersion = function () { + // Checks if unique IDs are in the project file + if (!json.metaData.nextUniqueId) { + var currentId = 0; + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].action.length; j++) { + json.data[i].action[j].id = currentId.toString(); + currentId++; + } + } + json.metaData.nextUniqueId = currentId; + } + }; + + /* Public API */ + + /* + * json variable generated from a JSON file. + * @param String stringJson String loaded from JSON file. + */ + this.loadJson = function (stringJson) { + json = JSON.parse(stringJson); + upgradeJsonVersion(); + }; + + /* + * Create a new presentation variable in the JSON file which will contain slides. + */ + this.createPresentation = function (width, height) { + json.metaData = {}; + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + json.metaData.nextUniqueId = 0; + json.data = new Array(); + }; + + /* + * Add a new slide in the presentation variable of the JSON file. + * @param int index wanted for the slide. + * @param String idSlide Unique identifier for the slide. + * @param String img Related to pathname of the image. + * @param double mouseX Abscissa mouse position in %. + * @param double mouseY Ordinate mouse position in %. + * @return Index of the newly added slide. + */ + this.addSlide = function (indexSlide, idSlide, img, mouseX, mouseY, speed) { + var slide = { + "object": new Array(), + "action": new Array() + }; + json.data.splice(indexSlide, 0, slide); + this.addObject(indexSlide, "background", idSlide, img); + this.addObject(indexSlide, "mouse"); + this.addAction(indexSlide, "move", json.data[indexSlide].object[1].id, "onClick", mouseX, mouseY, speed); + this.addAction(indexSlide, "appear", json.data[indexSlide].object[0].id, "afterPrevious"); + }; + + /* + * Object factory. + * Add a new Object in the slide idSlide. + * @param int idSlide + * @param string type + * Other params can be specified depending on the object's type. + */ + this.addObject = function (idSlide, type) { + var object = { + "type": type + }; + switch (type.toLowerCase()) { + case "background": + object.id = arguments[2] + json.data[idSlide].object.length; + object.img = arguments[3] || ""; + break; + case "mouse": + object.id = "mouse-cursor"; + break; + case "tooltip": + /* + * TODO: we'll need a more robust unique name + * when we start actually using this. + */ + object.id = "s" + idSlide + "-o" + json.data[idSlide].object.length; + object.text = arguments[2] || ""; + object.color = arguments[3] || null; + object.width = arguments[4] || ""; + json.data[idSlide].object.push(object); + var objectLength = json.data[idSlide].object.length; + var last = json.data[idSlide].object[objectLength-1]; + json.data[idSlide].object[objectLength-1] = + json.data[idSlide].object[objectLength-2]; + json.data[idSlide].object[objectLength-2] = last; + break; + } + if(type.toLowerCase() != "tooltip"){ + json.data[idSlide].object.push(object); + } + }; + + /* + * Action factory. + * Add a new Action in the slide idSlide whose target is the id of an object. + * Three types of trigger : "withPrevious", "afterPrevious", "onClick". + * @param int idSlide + * @param string type + * @param string target + * @param string trigger + * Other params can be specified depending on the object's type. + */ + this.addAction = function (idSlide, type, target, trigger) { + var action = { + "id": generateUniqueActionId(), + "type": type, + "target": target, + "trigger": trigger + }; + switch (type.toLowerCase()) { + case "appear": + action.abs = arguments[4] || 0.0; + action.ord = arguments[5] || 0.0; + action.duration = arguments[6] || 0; + break; + case "disappear": + action.duration = arguments[4] || 0; + break; + case "move": + action.finalAbs = arguments[4] || 0.0; + action.finalOrd = arguments[5] || 0.0; + action.speed = arguments[6] || 0; + break; + } + json.data[idSlide].action.push(action); + }; + + this.editMouse = function (idSlide, idAction, mouseX, mouseY) { + json.data[idSlide].action[idAction].finalAbs = mouseX; + json.data[idSlide].action[idAction].finalOrd = mouseY; + }; + + /* + * Sets a title for the presentation. + * @param String title Title to set. + */ + this.setTitle = function (title) { + json.metaData.title = title; + }; + + /* + * Sets an annotation for the presentation. + * @param String annotation Annotation to set. + */ + this.setAnnotation = function (annotation) { + json.metaData.annotation = annotation; + }; + + /* + * Inverts the two slides (their positions on the table). + * @param int idSlide1 Index of the first slide. + * @param int idSlide2 Index of the second slide. + */ + this.invertSlides = function (idSlide1, idSlide2) { + var tmp = json.data[idSlide1]; + json.data[idSlide1] = json.data[idSlide2]; + json.data[idSlide2] = tmp; + }; + + /* + * Inverts the two actions (their positions on the table). + * @param int idSlide + * @param int idAction1 + * @param int idAction2 + */ + this.invertActions = function (idSlide, idAction1, idAction2) { + var tmp = json.data[idSlide].action[idAction1]; + json.data[idSlide].action[idAction1] = json.data[idSlide].action[idAction2]; + json.data[idSlide].action[idAction2] = tmp; + }; + + /* + * Returns the actions on the specified slide. + * @returns {Array} + */ + this.getActionList = function (idSlide) { + return json.data[idSlide].action; + }; + + /* + * Catches all the objects of the presentation + * @returns {Array} List of objects of the presentation + */ + this.getObjectList = function () { + var objectList = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + var indexObject = 0; + while (json.data[indexSlide].object[indexObject]) { + objectList.push(json.data[indexSlide].object[indexObject]); + indexObject++; + } + indexSlide++; + } + return objectList; + }; + + /* + * Returns an array containing all the background images. + * @returns {Array} List of background images. + */ + this.getImageList = function () { + var list = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + list.push(json.data[indexSlide].object[0].img); + indexSlide++; + } + ; + return list; + }; + + /* + * Returns an object containing the id of the first background. + * @returns {string} Id of the first background. + */ + this.getInitialBackground = function () { + return json.data[0].object[0].id; + }; + + /* + * Returns an object containing the initial mouse position. + * @returns {object} Initial position of mouse. + */ + this.getInitialMousePos = function () { + var pos = {}; + pos.x = json.data[0].action[0].finalAbs; + pos.y = json.data[0].action[0].finalOrd; + return pos; + }; + + /* + * Removes the slide at the specified index. + * @param {int} idSlide + */ + this.removeSlide = function (idSlide) { + json.data.splice(idSlide, 1); + }; + + /* + * Removes the action at the specified slide. + * @param {int} idSlide + * @param {int} idAction + */ + this.removeAction = function (idSlide, idAction) { + json.data[idSlide].action.splice(idAction, 1); + }; + + /* + * Removes the specified object from the slide. + * Also removes all the actions attached to this object. + * @param {int} idSlide + * @param {int} idObject + */ + this.removeObject = function (idSlide, idObject) { + var removed = json.data[idSlide].object.splice(idObject, 1); + for (var i = 0; i < json.data.length; i++) { + var j = 0; + while (json.data[i].action[j]) { + if (json.data[i].action[j].target === removed.id) { + json.data[i].action.splice(j, 1); + } else { + j++; + } + } + } + }; + + /* + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * @returns {String} returns the index for the next slide. + */ + this.getNbSlide = function () { + return json.data.length; + }; + + /* + * @return {object} returns the object identified by idSlide + */ + this.getSlide = function (idSlide) { + return json.data[idSlide]; + }; + + /* + * Sets the size of images for the generated presentation. + * The parameters can be null : it means there are no + * requirement for this dimension. + * @param {int} width New width for the generated images. + * @param {int} height New height for the generated images. + */ + this.setImageSizeRequirements = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + /* + * Gets the width of images for the generated presentation. + * @return {int or null} Width of generated images. + */ + this.getImageWidth = function () { + return json.metaData.imageWidth; + }; + + /* + * Gets the height of images for the generated presentation. + * @return {int or null} Height of generated images. + */ + this.getImageHeight = function () { + return json.metaData.imageHeight; + }; + + /* + * Gets a background image (no one in particular, the first met). + * @return {string} The name of a background image. + */ + this.getABackgroundImage = function () { + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].object.length; j++) { + if (json.data[i].object[j].type === "background") { + return json.data[i].object[j].img; + } + } + } + return null; + }; + }; + + /* public API */ + + self.version = "0.0.1"; + + self.createScreencastGenerator = function createScreencastGenerator() { + return new DahuScreencastGenerator(); + }; + + self.createScreencastModel = function createScreencastModel() { + return new DahuScreencastModel(); + }; + + self.createScreencastExecutableModel = function createScreencastExecutableModel() { + return new DahuScreencastExecutableModel(); + }; + + self.createScreencastGeneratedModel = function createScreencastGeneratedModel() { + return new DahuScreencastGeneratedModel(); + }; + + return self; + })(); + + window.dahuapp = dahuapp; + +})(window, jQuery); \ No newline at end of file diff --git a/TP/TP01/P07/dahuapp.viewer.css b/TP/TP01/P07/dahuapp.viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ea934576dad6ca9263a6163de58f5fe4534d1f0b --- /dev/null +++ b/TP/TP01/P07/dahuapp.viewer.css @@ -0,0 +1,25 @@ +.object-list { + position: absolute; + margin: 0px; + padding: 0px; +} + +.mouse-cursor { + position: absolute; +} + +.control { + position: relative; +} + +.background { + position: absolute; +} + +.tooltip { + position: absolute; + width: 100px; + padding: 4px; + margin: 2px; + border: 2px black solid; +} \ No newline at end of file diff --git a/TP/TP01/P07/dahuapp.viewer.js b/TP/TP01/P07/dahuapp.viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..12ad03b2cdc503a8fd6ff3f5fdc2a74edbb36edb --- /dev/null +++ b/TP/TP01/P07/dahuapp.viewer.js @@ -0,0 +1,456 @@ +"use strict"; + +/** + * Dahuapp viewer module. + * + * @param dahuapp dahuapp object to augment with module. + * @param $ jQuery + * @returns dahuapp extended with viewer module. + */ + +(function(dahuapp, $) { + var viewer = (function() { + + var self = {}; + + var DahuViewerModel = function(select, getParams) { + + /* Private API */ + + var json = null; + var selector = select; + var parseAutoOption = function(name, defaultValue) { + var res = getParams[name]; + if (res == null) { + if (name == 'auto') { + return false; + } else { + return parseAutoOption('auto', defaultValue); + } + } + if (res.toLowerCase() === 'false') { + return false; + } + res = parseInt(res); + if (isNaN(res)) { + // e.g. ?autoplay or ?autoplay=true + return defaultValue; + } + return res; + } + + /* Whether to wait for "next" event between actions */ + var autoPlay = parseAutoOption('autoplay', 5000); + /* Whether to wait for "next" event on page load */ + var autoStart = parseAutoOption('autostart', 5000); + /* Whether to loop back to start at the end of presentation */ + var autoLoop = parseAutoOption('autoloop', 5000); + + var events = (function() { + var self = {}; + /* + * Creates a generic event. + */ + var createEvent = function() { + var callbacks = $.Callbacks(); + return { + publish: callbacks.fire, + subscribe: callbacks.add, + unsubscribe: callbacks.remove, + unsubscribeAll: callbacks.empty + }; + }; + /* + * Called when the button next is pressed. + */ + self.onNext = createEvent(); + /* + * Called when the button previous is pressed. + */ + self.onPrevious = createEvent(); + /* + * Called when an action is over. + */ + self.onActionOver = createEvent(); + /* + * Called when an action starts. + */ + self.onActionStart = createEvent(); + /* + * Called when at least one action was running and has finished. + */ + self.onAllActionFinish = createEvent(); + + return self; + })(); + + /* + * Variables used like index for methodes subscribed. + */ + var currentAction = 0; /* Action currently running */ + var nextAction = 0; /* Action to execute on 'Next' click */ + var nbActionsRunning = 0; + var previousAnchor = -1; /* Last entered anchor, only used in + * case the 'onhashchange' event is + * not supported by the web browser */ + + /* + * Functions to reinitialise running actions and subscribed + * callbacks (reinitialise is called once without stopping + * all the actions, so the two functions are separated). + */ + var stopAllActions = function() { + $(selector + " .object-list").children().stop(true, true); + reinitialiseCallbackLists(); + nbActionsRunning = 0; + }; + var reinitialiseCallbackLists = function() { + events.onActionStart.unsubscribeAll(); + events.onActionStart.subscribe(onActionStartEventHandler); + events.onAllActionFinish.unsubscribeAll(); + }; + + /* + * Timer used to program onNext event in autoplay mode. + */ + var playTimer = 0; + + /* + * Function used when an "onNextEvent" event is caught. + */ + var onNextEventHandler = function() { + /* + * If the user pressed "next" before an autoplay event + * is triggered, it replaces the autoplay event, hence + * cancels it: + */ + window.clearTimeout(playTimer); + + enterAnimationMode(); + stopAllActions(); + var tmpAction = nextAction; + var onlyWithPrevious = true; + nextAction++; + currentAction = nextAction; + while (json.action[currentAction] && onlyWithPrevious) { + switch (json.action[currentAction].trigger) { + case 'onClick': + nextAction = currentAction; + onlyWithPrevious = false; + break; + case 'withPrevious': + var tmp = currentAction; + /* + * We can't directly pass 'execute' as callback because we + * allow the 'execute' function to reference a property of the + * object (by using 'this.property') so we have to call the + * function in the containing object to make that available + */ + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + while (json.action[nextAction] && json.action[nextAction].trigger !== 'onClick') { + nextAction++; + } + onlyWithPrevious = false; + break; + } + currentAction++; + } + if (json.action[tmpAction]) { + launch(json.action[tmpAction]); + } + if (nextAction > json.action.length) { + nextAction = json.action.length; + } + }; + + /* + * Function used when an "onPreviousEvent" event is caught. + */ + var onPreviousEventHandler = function() { + stopAllActions(); + currentAction = nextAction - 1; + while (json.action[currentAction] && json.action[currentAction].trigger !== 'onClick') { + launchReverse(json.action[currentAction]); + currentAction--; + } + /* currentAction = -1 means that it's the beginning */ + if (currentAction > -1) { + launchReverse(json.action[currentAction]); + } + if (currentAction < 0) { + currentAction = 0; + } + nextAction = currentAction; + }; + + /* + * Function used when an "onActionOverEvent" event is caught. + */ + var onActionOverEventHandler = function() { + nbActionsRunning--; + if (nbActionsRunning === 0) { + events.onAllActionFinish.publish(events, selector); + reinitialiseCallbackLists(); + while (json.action[currentAction]) { + switch (json.action[currentAction].trigger) { + case 'onClick': + leaveAnimationMode(); + if (autoPlay && nbActionsRunning === 0) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoPlay); + } + return; + case 'withPrevious': + var tmp = currentAction; + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + currentAction++; + return; + } + currentAction++; + + } + if (autoLoop && nbActionsRunning === 0) { + setTimeout(function () { + resetPresentation(); + startPresentationMaybe(); + }, autoLoop); + } + } + leaveAnimationMode(); + }; + + /* + * Function used when an "onActionStartEvent" event is caught. + */ + var onActionStartEventHandler = function() { + nbActionsRunning++; + }; + + /* + * Enter and leave "animation" mode. The viewer is in + * animation mode when something is going on without human + * interaction (i.e. executing actions before the next + * "onClick"). + */ + var enterAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').hide(); + $(selector + ' .mouse-cursor-normal').show(); + }; + + var leaveAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').show(); + $(selector + ' .mouse-cursor-normal').hide(); + }; + + /* + * Function used to perform actions. + */ + var launch = function(action) { + action.execute(events, selector); + }; + var launchReverse = function(action) { + action.executeReverse(selector); + }; + + /* + * The two following methods each returns an array containing the + * actions to execute to reach the given anchor (respectively + * forward or backwards). + * + * If the given anchor matches none of the actions, then an empty + * array is returned. + */ + var getActionsToJumpForward = function(anchor) { + var actions = new Array(); + for (var i = nextAction; i < json.action.length; i++) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + if (json.action[i].id == anchor) { + return actions; + } else { + actions.push(json.action[i]); + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + var getActionsToJumpBackwards = function(anchor) { + var actions = new Array(); + for (var i = nextAction - 1; i >= 0; i--) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + actions.push(json.action[i]); + if (json.action[i].id == anchor) { + return actions; + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + + /* + * Updates the position of the presentation depending on the + * given anchor (next action wanted). + */ + var jumpToAnchor = function(anchor) { + if (anchor !== '') { + stopAllActions(); + if (anchor > nextAction) { + // forward + var actions = getActionsToJumpForward(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeImmediately(selector); + } + nextAction += actions.length; + } else { + // backwards + var actions = getActionsToJumpBackwards(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeReverse(selector); + } + nextAction -= actions.length; + } + } + }; + + var resetPresentation = function() { + window.clearTimeout(playTimer); + + currentAction = 0; + nextAction = 0; + nbActionsRunning = 0; + + /* + * At the beginning, the visible image is the first one of the presentation + */ + $(selector + " .object-list").children().hide(); + + $(selector + " ." + json.metaData.initialBackgroundId).show(); + + $(selector + " .mouse-cursor").css({ + 'top': (json.metaData.initialMouseY * json.metaData.imageHeight) + "px", + 'left': (json.metaData.initialMouseX * json.metaData.imageWidth) + "px" + }); + + $(selector + " .mouse-cursor").show(); + } + + var startPresentationMaybe = function() { + if (autoStart) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoStart); + } + } + + /* Public API */ + + this.loadUrl = function(url) { + var dataJson; + $.ajax({ + 'async': false, + 'global': false, + 'url': url, + 'dataType': "json", + 'success': function(data) { + dataJson = data; + } + }); + + load(dataJson); + }; + + this.load = function(dataJson) { + /* Transforms data JSON to executable functions for actions */ + var execModel = dahuapp.createScreencastExecutableModel(); + execModel.loadJson(dataJson); + json = execModel.getJson(); + }; + + this.start = function() { + + /* + * Subscription of methods to their events. + */ + events.onNext.subscribe(onNextEventHandler); + events.onPrevious.subscribe(onPreviousEventHandler); + events.onActionOver.subscribe(onActionOverEventHandler); + events.onActionStart.subscribe(onActionStartEventHandler); + + resetPresentation(); + + /* + * If an anchor has been specified, we place the presentation + * in the right position. + */ + jumpToAnchor(window.location.hash.substring(1)); + + /* + * If the anchor changes during the presentation, then the + * presentation is updated + */ + if ("onhashchange" in window) { + // event supported + window.onhashchange = function () { + jumpToAnchor(window.location.hash.substring(1)); + }; + } else { + // event not supported : periodical check + window.setInterval(function () { + if (window.location.hash.substring(1) !== previousAnchor) { + previousAnchor = window.location.hash.substring(1); + jumpToAnchor(window.location.hash.substring(1)); + } + }, 100); + } + + /* + * A click on the "next" button publishes a nextSlide event + */ + $(selector + " .next").click(function() { + events.onNext.publish(); + }); + + /* + * A click on the "previous" button publishes a previousSlide event + */ + $(selector + " .previous").click(function() { + events.onPrevious.publish(); + }); + + /* + * Everything is ready, show the presentation + * (hidden with style="display: none" from HTML). + */ + $("#loading").hide(); + $(selector + " .object-list").show(); + startPresentationMaybe(); + }; + }; + + self.createDahuViewer = function(selector, getParams) { + return new DahuViewerModel(selector, getParams); + }; + + return self; + })(); + + dahuapp.viewer = viewer; +})(dahuapp || {}, jQuery); diff --git a/TP/TP01/P07/img/19b1d70a-cda5-4dcc-39dc-39cc6ba9db54.png b/TP/TP01/P07/img/19b1d70a-cda5-4dcc-39dc-39cc6ba9db54.png new file mode 100644 index 0000000000000000000000000000000000000000..df3f343f817bc7a8c9cc0aafedfa9dcdf977f624 Binary files /dev/null and b/TP/TP01/P07/img/19b1d70a-cda5-4dcc-39dc-39cc6ba9db54.png differ diff --git a/TP/TP01/P07/img/35b70b02-d1ba-934a-f7ae-8c67f5b6d591.png b/TP/TP01/P07/img/35b70b02-d1ba-934a-f7ae-8c67f5b6d591.png new file mode 100644 index 0000000000000000000000000000000000000000..fd9aa65497315f24f529a59113a25700cc8c2105 Binary files /dev/null and b/TP/TP01/P07/img/35b70b02-d1ba-934a-f7ae-8c67f5b6d591.png differ diff --git a/TP/TP01/P07/img/383e00ab-046d-3c6a-1b47-afb0f883d8d6.png b/TP/TP01/P07/img/383e00ab-046d-3c6a-1b47-afb0f883d8d6.png new file mode 100644 index 0000000000000000000000000000000000000000..2e45eada327109ab094698d543044ff0ec70b769 Binary files /dev/null and b/TP/TP01/P07/img/383e00ab-046d-3c6a-1b47-afb0f883d8d6.png differ diff --git a/TP/TP01/P07/img/3e70d3db-b54f-2223-ff57-003273c7f1fd.png b/TP/TP01/P07/img/3e70d3db-b54f-2223-ff57-003273c7f1fd.png new file mode 100644 index 0000000000000000000000000000000000000000..6d6429eeef4aedc8b53da9087c45faee341c708a Binary files /dev/null and b/TP/TP01/P07/img/3e70d3db-b54f-2223-ff57-003273c7f1fd.png differ diff --git a/TP/TP01/P07/img/42c31ce5-a47e-ad8f-d1b7-12191c9d464b.png b/TP/TP01/P07/img/42c31ce5-a47e-ad8f-d1b7-12191c9d464b.png new file mode 100644 index 0000000000000000000000000000000000000000..1823147cd445934dc31d948105636924adba135a Binary files /dev/null and b/TP/TP01/P07/img/42c31ce5-a47e-ad8f-d1b7-12191c9d464b.png differ diff --git a/TP/TP01/P07/img/494d5fbc-7710-81cb-2bd1-9b7f5e04cfbb.png b/TP/TP01/P07/img/494d5fbc-7710-81cb-2bd1-9b7f5e04cfbb.png new file mode 100644 index 0000000000000000000000000000000000000000..e7812f5bd814a42e72ccf713141cf5ad64877c58 Binary files /dev/null and b/TP/TP01/P07/img/494d5fbc-7710-81cb-2bd1-9b7f5e04cfbb.png differ diff --git a/TP/TP01/P07/img/5303de8b-2766-351a-f426-c109e4df9d32.png b/TP/TP01/P07/img/5303de8b-2766-351a-f426-c109e4df9d32.png new file mode 100644 index 0000000000000000000000000000000000000000..76d27cb1f9c791369dfb8f247381582588f428bd Binary files /dev/null and b/TP/TP01/P07/img/5303de8b-2766-351a-f426-c109e4df9d32.png differ diff --git a/TP/TP01/P07/img/54037052-0fd4-1be4-b371-cac4e8c5f7ca.png b/TP/TP01/P07/img/54037052-0fd4-1be4-b371-cac4e8c5f7ca.png new file mode 100644 index 0000000000000000000000000000000000000000..89355470649d0a7d0b957595b6c9ed58d866f4eb Binary files /dev/null and b/TP/TP01/P07/img/54037052-0fd4-1be4-b371-cac4e8c5f7ca.png differ diff --git a/TP/TP01/P07/img/6b93f0f7-10f2-8bb5-85a6-428b72c183cb.png b/TP/TP01/P07/img/6b93f0f7-10f2-8bb5-85a6-428b72c183cb.png new file mode 100644 index 0000000000000000000000000000000000000000..0232afa54a03e3928c7addbba07b4ff9c4557747 Binary files /dev/null and b/TP/TP01/P07/img/6b93f0f7-10f2-8bb5-85a6-428b72c183cb.png differ diff --git a/TP/TP01/P07/img/6bdbf5c7-a99a-1f31-0046-461682be575b.png b/TP/TP01/P07/img/6bdbf5c7-a99a-1f31-0046-461682be575b.png new file mode 100644 index 0000000000000000000000000000000000000000..a9c2dbac8ef099da5444e0d9146ee2f09408bc2e Binary files /dev/null and b/TP/TP01/P07/img/6bdbf5c7-a99a-1f31-0046-461682be575b.png differ diff --git a/TP/TP01/P07/img/70d9c961-62ff-9470-06da-617bab7e1041.png b/TP/TP01/P07/img/70d9c961-62ff-9470-06da-617bab7e1041.png new file mode 100644 index 0000000000000000000000000000000000000000..f6709afd85708e444f7492fa9e37b8f01aad4e5e Binary files /dev/null and b/TP/TP01/P07/img/70d9c961-62ff-9470-06da-617bab7e1041.png differ diff --git a/TP/TP01/P07/img/826ee375-9184-a716-a352-586fbb1d439d.png b/TP/TP01/P07/img/826ee375-9184-a716-a352-586fbb1d439d.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b1fff04fa97256ef2080252656d58b35df90e1 Binary files /dev/null and b/TP/TP01/P07/img/826ee375-9184-a716-a352-586fbb1d439d.png differ diff --git a/TP/TP01/P07/img/87f55d84-813d-19ce-b06f-cf5b79be31d7.png b/TP/TP01/P07/img/87f55d84-813d-19ce-b06f-cf5b79be31d7.png new file mode 100644 index 0000000000000000000000000000000000000000..3644839b3266d94905c78192f8fa9bd4ce3998c6 Binary files /dev/null and b/TP/TP01/P07/img/87f55d84-813d-19ce-b06f-cf5b79be31d7.png differ diff --git a/TP/TP01/P07/img/b777af85-02d8-11ad-969c-cf3c589cd92c.png b/TP/TP01/P07/img/b777af85-02d8-11ad-969c-cf3c589cd92c.png new file mode 100644 index 0000000000000000000000000000000000000000..62c78ced34f90d859c921f1dbe01366e2de00e93 Binary files /dev/null and b/TP/TP01/P07/img/b777af85-02d8-11ad-969c-cf3c589cd92c.png differ diff --git a/TP/TP01/P07/img/cf8c5592-1b83-11db-194b-4e27e48986f3.png b/TP/TP01/P07/img/cf8c5592-1b83-11db-194b-4e27e48986f3.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b1fff04fa97256ef2080252656d58b35df90e1 Binary files /dev/null and b/TP/TP01/P07/img/cf8c5592-1b83-11db-194b-4e27e48986f3.png differ diff --git a/TP/TP01/P07/img/cursor-pause.png b/TP/TP01/P07/img/cursor-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9c93cc142f4326a188eafc3c0fe96f2975dcab0c Binary files /dev/null and b/TP/TP01/P07/img/cursor-pause.png differ diff --git a/TP/TP01/P07/img/cursor.png b/TP/TP01/P07/img/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..5b4a20e63078ce18bb11a4e601a1994b261522ef Binary files /dev/null and b/TP/TP01/P07/img/cursor.png differ diff --git a/TP/TP01/P07/img/eb2b9cec-88ce-fd11-0b2d-c0d1706b65ec.png b/TP/TP01/P07/img/eb2b9cec-88ce-fd11-0b2d-c0d1706b65ec.png new file mode 100644 index 0000000000000000000000000000000000000000..a2b1fff04fa97256ef2080252656d58b35df90e1 Binary files /dev/null and b/TP/TP01/P07/img/eb2b9cec-88ce-fd11-0b2d-c0d1706b65ec.png differ diff --git a/TP/TP01/P07/img/f09992e3-2ec1-fc7b-307e-01e4abe14557.png b/TP/TP01/P07/img/f09992e3-2ec1-fc7b-307e-01e4abe14557.png new file mode 100644 index 0000000000000000000000000000000000000000..5a807adceca77b61b3c5010a101144fff5a88fed Binary files /dev/null and b/TP/TP01/P07/img/f09992e3-2ec1-fc7b-307e-01e4abe14557.png differ diff --git a/TP/TP01/P07/index.html b/TP/TP01/P07/index.html new file mode 100644 index 0000000000000000000000000000000000000000..f4a529889b3ea28b4d084f30bcd808fad96b71ab --- /dev/null +++ b/TP/TP01/P07/index.html @@ -0,0 +1,427 @@ +<!DOCTYPE html> + +<html lang="en"> + +<head> +<title>Dahu Presentation +</title> +<meta charset="utf-8"> +<script src="http://code.jquery.com/jquery-1.9.1.min.js" type="text/javascript"> +</script> +<script src="parse-search.js" type="text/javascript"> +</script> + +<link rel="stylesheet" href="dahuapp.viewer.css"><style>.s0-o2{background-color: #FFFFDD;width: 240px} +.s1-o2{background-color: #FFFFDD;width: 240px} +.s2-o2{background-color: #FFFFDD;width: 240px} +.s3-o2{background-color: #FFFFDD;width: 240px} +.s4-o2{background-color: #FFFFDD;width: 240px} +.s5-o2{background-color: #FFFFDD;width: 240px} +.s6-o2{background-color: #FFFFDD;width: 240px} +.s7-o2{background-color: #FFFFDD;width: 240px} +.s8-o2{background-color: #FFFFDD;width: 240px} +.s9-o2{background-color: #FFFFDD;width: 240px} +.s10-o2{background-color: #FFFFDD;width: 240px} +.s11-o2{background-color: #FFFFDD;width: 240px} +</style> +</head> + +<body> + +<div id="my-dahu-presentation"> + +<div id="loading">Loading presentation... +</div> + +<div class="object-list" style="display: none"> +<img src="img/6bdbf5c7-a99a-1f31-0046-461682be575b.png" alt="img/6bdbf5c7-a99a-1f31-0046-461682be575b.png" class="background 6bdbf5c7-a99a-1f31-0046-461682be575b0"> + +<div class="tooltip s0-o2">Déposer un bloc Integrator. +</div> +<img src="img/494d5fbc-7710-81cb-2bd1-9b7f5e04cfbb.png" alt="img/494d5fbc-7710-81cb-2bd1-9b7f5e04cfbb.png" class="background 494d5fbc-7710-81cb-2bd1-9b7f5e04cfbb0"> + +<div class="tooltip s1-o2">Déposer un bloc Gain (multiplication par une constante). +</div> +<img src="img/19b1d70a-cda5-4dcc-39dc-39cc6ba9db54.png" alt="img/19b1d70a-cda5-4dcc-39dc-39cc6ba9db54.png" class="background 19b1d70a-cda5-4dcc-39dc-39cc6ba9db540"> + +<div class="tooltip s2-o2">Tourner la représentation graphique du bloc Gain. +</div> +<img src="img/f09992e3-2ec1-fc7b-307e-01e4abe14557.png" alt="img/f09992e3-2ec1-fc7b-307e-01e4abe14557.png" class="background f09992e3-2ec1-fc7b-307e-01e4abe145570"> + +<div class="tooltip s3-o2">Tourner la représentation graphique du bloc Gain. +</div> +<img src="img/3e70d3db-b54f-2223-ff57-003273c7f1fd.png" alt="img/3e70d3db-b54f-2223-ff57-003273c7f1fd.png" class="background 3e70d3db-b54f-2223-ff57-003273c7f1fd0"> + +<div class="tooltip s4-o2">Choisir le contenu de la variable K comme valeur du Gain. +</div> +<img src="img/6b93f0f7-10f2-8bb5-85a6-428b72c183cb.png" alt="img/6b93f0f7-10f2-8bb5-85a6-428b72c183cb.png" class="background 6b93f0f7-10f2-8bb5-85a6-428b72c183cb0"> + +<div class="tooltip s5-o2">Définir la variable K dans MatLab avec la valeur -1. +</div> +<img src="img/b777af85-02d8-11ad-969c-cf3c589cd92c.png" alt="img/b777af85-02d8-11ad-969c-cf3c589cd92c.png" class="background b777af85-02d8-11ad-969c-cf3c589cd92c0"> + +<div class="tooltip s6-o2">Connecter les ports d'entrée et de sortie pour faire une boucle correspondant à l'équation aux dérivées ordinaires (dx/dt + K x = 0). +</div> +<img src="img/5303de8b-2766-351a-f426-c109e4df9d32.png" alt="img/5303de8b-2766-351a-f426-c109e4df9d32.png" class="background 5303de8b-2766-351a-f426-c109e4df9d320"> + +<div class="tooltip s7-o2">Nommer les signaux pour identifier x. +</div> +<img src="img/35b70b02-d1ba-934a-f7ae-8c67f5b6d591.png" alt="img/35b70b02-d1ba-934a-f7ae-8c67f5b6d591.png" class="background 35b70b02-d1ba-934a-f7ae-8c67f5b6d5910"> + +<div class="tooltip s8-o2">Ajouter un bloc Oscilloscope pour observer la valeur de x. +</div> +<img src="img/54037052-0fd4-1be4-b371-cac4e8c5f7ca.png" alt="img/54037052-0fd4-1be4-b371-cac4e8c5f7ca.png" class="background 54037052-0fd4-1be4-b371-cac4e8c5f7ca0"> + +<div class="tooltip s9-o2">Démarrer la simulation. x reste nul car la valeur initiale vaut 0. +</div> +<img src="img/42c31ce5-a47e-ad8f-d1b7-12191c9d464b.png" alt="img/42c31ce5-a47e-ad8f-d1b7-12191c9d464b.png" class="background 42c31ce5-a47e-ad8f-d1b7-12191c9d464b0"> + +<div class="tooltip s10-o2">Modifier la valeur initiale du bloc Integrator. +</div> +<img src="img/826ee375-9184-a716-a352-586fbb1d439d.png" alt="img/826ee375-9184-a716-a352-586fbb1d439d.png" class="background 826ee375-9184-a716-a352-586fbb1d439d0"> + +<div class="tooltip s11-o2">Démarrer la simulation. +</div> + +<div class="mouse-cursor"> +<img src="img/cursor.png" alt="img/cursor.png" class="mouse-cursor-normal"> +<img src="img/cursor-pause.png" alt="img/cursor-pause.png" style="display: none" class="mouse-cursor-pause"> +</div> +</div> + +<div class="control" style="top: 616px;"> +<button class="previous">Previous +</button> +<button class="next">Next +</button> +</div> +</div> +<script src="dahuapp.js" type="text/javascript"> +</script> +<script src="dahuapp.viewer.js" type="text/javascript"> +</script> +<script type="text/javascript">(function($) { + var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams); + myPresentation.load({ + "metaData": { + "imageWidth": 800, + "imageHeight": 600, + "initialBackgroundId": "6bdbf5c7-a99a-1f31-0046-461682be575b0", + "initialMouseX": 0.7736111111111111, + "initialMouseY": 0.43222222222222223 + }, + "action": [ + { + "id": "35", + "type": "appear", + "target": "s0-o2", + "trigger": "afterPrevious", + "abs": 0.18666666666666668, + "ord": 0.14375, + "duration": 400 + }, + { + "id": "5", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.32083333333333336, + "finalOrd": 0.41555555555555557, + "speed": 0.8 + }, + { + "id": "6", + "type": "appear", + "target": "494d5fbc-7710-81cb-2bd1-9b7f5e04cfbb0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "36", + "type": "appear", + "target": "s1-o2", + "trigger": "afterPrevious", + "abs": 0.095, + "ord": 0.20375, + "duration": 400 + }, + { + "id": "7", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.5555555555555556, + "finalOrd": 0.6522222222222223, + "speed": 0.8 + }, + { + "id": "8", + "type": "appear", + "target": "19b1d70a-cda5-4dcc-39dc-39cc6ba9db540", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "37", + "type": "appear", + "target": "s2-o2", + "trigger": "afterPrevious", + "abs": 0.35833333333333334, + "ord": 0.32, + "duration": 400 + }, + { + "id": "9", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.5791666666666667, + "finalOrd": 0.6511111111111111, + "speed": 0.8 + }, + { + "id": "10", + "type": "appear", + "target": "f09992e3-2ec1-fc7b-307e-01e4abe145570", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "38", + "type": "appear", + "target": "s3-o2", + "trigger": "afterPrevious", + "abs": 0.34, + "ord": 0.32125, + "duration": 400 + }, + { + "id": "11", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3611111111111111, + "finalOrd": 0.38, + "speed": 0.8 + }, + { + "id": "12", + "type": "appear", + "target": "3e70d3db-b54f-2223-ff57-003273c7f1fd0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "39", + "type": "appear", + "target": "s4-o2", + "trigger": "afterPrevious", + "abs": 0.19833333333333333, + "ord": 0.19875, + "duration": 400 + }, + { + "id": "13", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3347222222222222, + "finalOrd": 0.3511111111111111, + "speed": 0.8 + }, + { + "id": "14", + "type": "appear", + "target": "6b93f0f7-10f2-8bb5-85a6-428b72c183cb0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "40", + "type": "appear", + "target": "s5-o2", + "trigger": "afterPrevious", + "abs": 0.10333333333333333, + "ord": 0.18, + "duration": 400 + }, + { + "id": "15", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3298611111111111, + "finalOrd": 0.2388888888888889, + "speed": 0.8 + }, + { + "id": "16", + "type": "appear", + "target": "b777af85-02d8-11ad-969c-cf3c589cd92c0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "41", + "type": "appear", + "target": "s6-o2", + "trigger": "afterPrevious", + "abs": 0.185, + "ord": 0.18125, + "duration": 400 + }, + { + "id": "17", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3597222222222222, + "finalOrd": 0.38555555555555554, + "speed": 0.8 + }, + { + "id": "18", + "type": "appear", + "target": "5303de8b-2766-351a-f426-c109e4df9d320", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "42", + "type": "appear", + "target": "s7-o2", + "trigger": "afterPrevious", + "abs": 0.09833333333333333, + "ord": 0.18375, + "duration": 400 + }, + { + "id": "21", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3951388888888889, + "finalOrd": 0.38333333333333336, + "speed": 0.8 + }, + { + "id": "22", + "type": "appear", + "target": "35b70b02-d1ba-934a-f7ae-8c67f5b6d5910", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "43", + "type": "appear", + "target": "s8-o2", + "trigger": "afterPrevious", + "abs": 0.16333333333333333, + "ord": 0.195, + "duration": 400 + }, + { + "id": "23", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.17708333333333334, + "finalOrd": 0.6644444444444444, + "speed": 0.8 + }, + { + "id": "24", + "type": "appear", + "target": "54037052-0fd4-1be4-b371-cac4e8c5f7ca0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "44", + "type": "appear", + "target": "s9-o2", + "trigger": "afterPrevious", + "abs": 0.17833333333333334, + "ord": 0.1825, + "duration": 400 + }, + { + "id": "25", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3875, + "finalOrd": 0.24, + "speed": 0.8 + }, + { + "id": "26", + "type": "appear", + "target": "42c31ce5-a47e-ad8f-d1b7-12191c9d464b0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "45", + "type": "appear", + "target": "s10-o2", + "trigger": "afterPrevious", + "abs": 0.36333333333333334, + "ord": 0.13, + "duration": 400 + }, + { + "id": "29", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.1798611111111111, + "finalOrd": 0.6666666666666666, + "speed": 0.8 + }, + { + "id": "30", + "type": "appear", + "target": "826ee375-9184-a716-a352-586fbb1d439d0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "46", + "type": "appear", + "target": "s11-o2", + "trigger": "afterPrevious", + "abs": 0.165, + "ord": 0.19125, + "duration": 400 + } + ] +}); + myPresentation.start(); +})(jQuery); + +</script> +</body> +</html> \ No newline at end of file diff --git a/TP/TP01/P07/parse-search.js b/TP/TP01/P07/parse-search.js new file mode 100644 index 0000000000000000000000000000000000000000..e7d01c07f6a5d45b9fcabd5d271a8c6cfc5f00e2 --- /dev/null +++ b/TP/TP01/P07/parse-search.js @@ -0,0 +1,14 @@ +// Adapted from http://stackoverflow.com/questions/3234125/creating-array-from-window-location-hash +(function () { + var search = window.location.search.slice(1); + var array = search.split("&"); + + var values, form_data = {}; + + for (var i = 0; i < array.length; i += 1) { + values = array[i].split("="); + form_data[values[0]] = unescape(values[1]); + } + window.getParams = form_data; +}()) + diff --git a/TP/TP01/P08/dahuapp.js b/TP/TP01/P08/dahuapp.js new file mode 100644 index 0000000000000000000000000000000000000000..41c69e9169345a9a6703325d5557a4cc36913e19 --- /dev/null +++ b/TP/TP01/P08/dahuapp.js @@ -0,0 +1,880 @@ +"use strict"; + +/** + * Dahuapp core module. + * + * @param window window javascript object. + * @param $ jQuery + * @returns dahuapp core module. + */ +(function (window, $) { + var dahuapp = (function () { + + var self = {}; + + /* private API */ + + var DahuScreencastGenerator = function () { + + /* + * Format the specified string in a readable format. + */ + function htmlFormat(htmlString) { + var i; + var readableHTML = htmlString; + var lb = '\n'; + var htags = ["<html", "</html>", "</head>", "<title", "</title>", "<meta", "<link", "</body>"]; + for (i = 0; i < htags.length; ++i) { + var hhh = htags[i]; + readableHTML = readableHTML.replace(new RegExp(hhh, 'gi'), lb + hhh); + } + var btags = ["</div>", "</section>", "</span>", "<br>", "<br />", "<blockquote", "</blockquote>", "<ul", "</ul>", "<ol", "</ol>", "<li", "<\!--", "<script", "</script>"]; + for (i = 0; i < btags.length; ++i) { + var bbb = btags[i]; + readableHTML = readableHTML.replace(new RegExp(bbb, 'gi'), lb + bbb); + } + var ftags = ["<img", "<legend", "</legend>", "<button", "</button>"]; + for (i = 0; i < ftags.length; ++i) { + var fff = ftags[i]; + readableHTML = readableHTML.replace(new RegExp(fff, 'gi'), lb + fff); + } + var xtags = ["<body", "<head", "<div", "<section", "<span", "<p"]; + for (i = 0; i < xtags.length; ++i) { + var xxx = xtags[i]; + readableHTML = readableHTML.replace(new RegExp(xxx, 'gi'), lb + lb + xxx); + } + return readableHTML; + } + + /* + * Generates the html header. + */ + var generateHtmlHeader = function ($generated, cssGen) { + $('head', $generated) + .append($(document.createElement('title')) + .append("Dahu Presentation"))/* TODO: make this customizable */ + .append($(document.createElement('meta')) + .attr({'charset': 'utf-8'})) + .append($(document.createElement('script')) + .attr({'src': 'http://code.jquery.com/jquery-1.9.1.min.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'parse-search.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('link')) + .attr({'rel': 'stylesheet', 'href': 'dahuapp.viewer.css'})) + .append($(document.createElement('style')) + .append(cssGen)); + }; + + /* + * Generates the objects. + */ + + var generateHtmlBackgroundImage = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('img')) + .attr({'src': object.img, 'alt': object.img, 'class': 'background ' + object.id})); + }; + var generateHtmlTooltip = function ($generated, object) { + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'tooltip ' + object.id}) + .append(object.text)); + }; + + var generateCssTooltip = function ($generated, object) { + var style = []; + + if( object.color != null ) { + style.push('background-color: ' + object.color); + } + if( object.width != null ) { + style.push('width: ' + object.width); + } + + if( style.length != 0 ) { + $generated.append( + '.' + object.id + '{' + style.join(';') + '}\n'); + } + + return $generated; + }; + + /* + * Returns the code used to call the viewer to the presentation. + */ + var getBasicCallCode = function (jsonModel) { + var code = '(function($) {\n'; + code += ' var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams);\n'; + code += ' myPresentation.load(' + jsonModel + ');\n'; + code += ' myPresentation.start();\n'; + code += '})(jQuery);\n'; + return code; + }; + + /* + * Generates the html body. + */ + var generateHtmlBody = function ($generated, jsonModel, jsonGen) { + $('body', $generated) + /* We could use a <section> here too, but it does not work with MS IE 8. + Alternatively, adding this in the header would work: + + <!--[if lt IE 9]> + <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + */ + .append($(document.createElement('div')) + .attr({'id': 'my-dahu-presentation'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'src': 'dahuapp.viewer.js'}) + .attr({'type': 'text/javascript'})) + .append($(document.createElement('script')) + .attr({'type': 'text/javascript'}) + .append(getBasicCallCode(jsonGen))); + $('#my-dahu-presentation', $generated) + .append($(document.createElement('div')) + .attr({'id': 'loading'}).append("Loading presentation...")) + .append($(document.createElement('div')) + .attr({'class': 'object-list', + 'style': 'display: none'})) + .append($(document.createElement('div')) + .attr({'class': 'control'})); + + /* Adding the objects to the page */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "background": + generateHtmlBackgroundImage($generated, object); + break; + case "tooltip": + generateHtmlTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + /* Warning here, i'm not sure if $.each is always over, here */ + + /* Adding the control buttons to the page */ + $('.control', $generated) + .css({'top': (jsonModel.getImageHeight() + 16) + 'px'}) + .append($(document.createElement('button')) + .attr({'class': 'previous'}) + .append('Previous')) + .append($(document.createElement('button')) + .attr({'class': 'next'}) + .append('Next')); + + /* Adding the mouse cursor image */ + $('.object-list', $generated) + .append($(document.createElement('div')) + .attr({'class': 'mouse-cursor'}) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor.png', 'alt': 'img/cursor.png', 'class': 'mouse-cursor-normal'})) + .append($(document.createElement('img')) + .attr({'src': 'img/cursor-pause.png', 'alt': 'img/cursor-pause.png', + 'style': 'display: none', 'class': 'mouse-cursor-pause'}))); + }; + + /* + * Generates the css String with the Json model. + */ + this.generateCssString = function (jsonModel) { + var $generated = $('<style></style>'); + + /* Going through each object */ + $.each(jsonModel.getObjectList(), function (id, object) { + switch (object.type) { + case "tooltip": + generateCssTooltip($generated, object); + break; + /* no mouse image generated here */ + } + }); + + return $generated.text(); + } + + /* + * Generates the html String with the Json model. + */ + this.generateHtmlString = function (jsonModel, jsonGen, cssGen) { + /* Initialising the compilation area */ + var $generated = $(document.createElement('div')); + + /* We create the html using the json */ + $generated.append($(document.createElement('html')) + .attr({'lang': 'en'})); + $('html', $generated) + .append($(document.createElement('head'))) + .append($(document.createElement('body'))); + + generateHtmlHeader($generated, cssGen); + generateHtmlBody($generated, jsonModel, jsonGen); + + var result = htmlFormat($generated.html()); + + return '<!DOCTYPE html>\n' + result; + }; + + /* + * Generates the generated JSON using the JSONmodel. + * @param {object} jsonModel The json model to transform. + * @param {java.awt.Dimension} imgDim The dimension of images. + */ + this.generateJsonString = function (jsonModel, imgDim) { + var generated = self.createScreencastGeneratedModel(); + generated.setImageSize(imgDim.width, imgDim.height); + generated.setInitialBackground(jsonModel.getInitialBackground()); + generated.setInitialMousePos(jsonModel.getInitialMousePos()); + for (var i = 0; i < jsonModel.getNbSlide(); i++) { + var actionList = jsonModel.getActionList(i); + for (var j = 0; j < actionList.length; j++) { + /* + * We don't add the two first actions of the first slide + * because they are present in the presentation metadata. + * It corresponds to the mouse initial pos and first background. + */ + if (i > 0 || j > 1) { + generated.addAction(actionList[j], imgDim.width, imgDim.height); + } + } + } + return generated.getJson(); + }; + }; + + /* + * Model for a JSON object that will only be used by the viewer, never + * saved on a file, used to transform the properties of actions + * specified on the JSON file of a presentation to executable + * functions for each action. + */ + var DahuScreencastExecutableModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* + * Creates a functions representing the specified action, and adds + * it to this object. + * @param {object} action + */ + var addExecutableAction = function (action) { + var executableAction = { + 'id': action.id, + 'trigger': action.trigger, + 'target': action.target, + 'delayAfter': action.delayAfter, + 'doneFunction': function (events, selector) { + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.delayAfter); + } + }; + if (executableAction.delayAfter == null) { + executableAction.delayAfter = 200; + } + switch (action.type.toLowerCase()) { + case "appear": + executableAction.abs = (action.abs * json.metaData.imageWidth) + 'px'; + executableAction.ord = (action.ord * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + $(sel).css({ + 'left': this.abs, + 'top': this.ord + }); + $(sel).show(); + }; + break; + case "disappear": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + $(selector + ' .' + this.target).hide(this.duration, function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).show(); + }; + executableAction.executeImmediately = function (selector) { + $(selector + ' .' + this.target).hide(); + }; + break; + case "move": + executableAction.finalAbs = (action.finalAbs * json.metaData.imageWidth) + 'px'; + executableAction.finalOrd = (action.finalOrd * json.metaData.imageHeight) + 'px'; + executableAction.duration = action.duration; + executableAction.speed = action.speed; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + if (this.duration == null) { + var initialAbsPix = this.initialAbs.replace('px', ''); + var initialOrdPix = this.initialOrd.replace('px', ''); + var finalAbsPix = this.finalAbs.replace('px', ''); + var finalOrdPix = this.finalOrd.replace('px', ''); + var distance = Math.sqrt(Math.pow(finalAbsPix - initialAbsPix, 2) + + Math.pow(finalOrdPix - initialOrdPix, 2)); + if (!this.speed) { + this.speed = .8; // in pixel per milisecond: fast, but not too much. + } + this.duration = distance + this.speed; + if (this.duration < 200) { // Slow down a bit for short distances. + this.duration = 200; + } + } + $(sel).animate({ + 'left': this.finalAbs, + 'top': this.finalOrd + }, this.duration, 'linear', function () { + executableAction.doneFunction(events, selector); + }); + }; + executableAction.executeReverse = function (selector) { + $(selector + ' .' + this.target).css({ + 'left': this.initialAbs, + 'top': this.initialOrd + }); + }; + executableAction.executeImmediately = function (selector) { + var sel = selector + ' .' + this.target; + this.initialAbs = $(sel).css('left'); + this.initialOrd = $(sel).css('top'); + $(sel).css({ + 'left': this.finalAbs, + 'top': this.finalOrd + }); + }; + break; + case "delay": + executableAction.duration = action.duration; + executableAction.execute = function (events, selector) { + events.onActionStart.publish(events, selector); + setTimeout(function () { + events.onActionOver.publish(events, selector); + }, this.duration); + }; + executableAction.executeReverse = function (selector) { + // Nothing! + }; + executableAction.executeImmediately = function (selector) { + // Nothing too! + }; + break; + } + json.action.push(executableAction); + }; + + /* Public API */ + + /* + * Loads the specified JSON read from a 'presentation.json' file, + * and stores the functions representing each actions in an object. + * @param {object} jsonToLoad + */ + this.loadJson = function (jsonToLoad) { + json.metaData = jsonToLoad.metaData; + for (var i = 0; i < jsonToLoad.action.length; i++) { + addExecutableAction(jsonToLoad.action[i]); + } + }; + + /* + * Returns the object containing the functions. + */ + this.getJson = function () { + return json; + }; + }; + + /* + * Used to transform the 'dahu' file to a JSON file used by the viewer, + * which only contains some metaData and a list of actions. + */ + var DahuScreencastGeneratedModel = function () { + + /* Private API */ + + var json = { + metaData: {}, + action: new Array() + }; + + /* Public API */ + + /* + * Returns a string representation of this json. + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * Setters for the generated json metadata. + */ + this.setImageSize = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + this.setInitialMousePos = function (pos) { + json.metaData.initialMouseX = pos.x; + json.metaData.initialMouseY = pos.y; + }; + + this.setInitialBackground = function (id) { + json.metaData.initialBackgroundId = id; + }; + + this.addAction = function (action) { + json.action.push(action); + }; + + /* + * Transforms a JSON containing action properties to a JSON containing + * the execution functions. + * @param {Object} json + * @returns {Object} A json object containing the execution functions + * for all the actions of the presentation. + */ + this.toExecutableList = function (json) { + var executableList = { + metaData: json.metaData, + action: new Array() + }; + for (var i = 0; i < json.action.length; i++) { + addExecutableAction(executableList, json.action[i]); + } + return executableList; + }; + }; + + /* + * Represents a 'dahu' file for a project. + */ + var DahuScreencastModel = function () { + + /* Private API */ + + var json = {}; + + /* + * Generates a unique action ID. + * + * With this implementation, this ID is unique as long as the user + * doesn't replace it manually with a not kind value or replace + * the nextUniqueId with bad intentions. + * But maybe that a UUID is a bit tiresome to put as an anchor... + */ + var generateUniqueActionId = function () { + json.metaData.nextUniqueId++; + return json.metaData.nextUniqueId.toString(); + }; + + /* + * This method checks if the json representing a dahu project is + * in the good version. It's in case a project file was created + * with a previous version of Dahu, and that some fields are + * missing. + * + * It doesn't control each field (at the moment) but only the + * fields that can be missing due to a new Dahu version and not + * to a manual editing. + * + * This method doesn't check any Json syntax or something like that. + */ + var upgradeJsonVersion = function () { + // Checks if unique IDs are in the project file + if (!json.metaData.nextUniqueId) { + var currentId = 0; + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].action.length; j++) { + json.data[i].action[j].id = currentId.toString(); + currentId++; + } + } + json.metaData.nextUniqueId = currentId; + } + }; + + /* Public API */ + + /* + * json variable generated from a JSON file. + * @param String stringJson String loaded from JSON file. + */ + this.loadJson = function (stringJson) { + json = JSON.parse(stringJson); + upgradeJsonVersion(); + }; + + /* + * Create a new presentation variable in the JSON file which will contain slides. + */ + this.createPresentation = function (width, height) { + json.metaData = {}; + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + json.metaData.nextUniqueId = 0; + json.data = new Array(); + }; + + /* + * Add a new slide in the presentation variable of the JSON file. + * @param int index wanted for the slide. + * @param String idSlide Unique identifier for the slide. + * @param String img Related to pathname of the image. + * @param double mouseX Abscissa mouse position in %. + * @param double mouseY Ordinate mouse position in %. + * @return Index of the newly added slide. + */ + this.addSlide = function (indexSlide, idSlide, img, mouseX, mouseY, speed) { + var slide = { + "object": new Array(), + "action": new Array() + }; + json.data.splice(indexSlide, 0, slide); + this.addObject(indexSlide, "background", idSlide, img); + this.addObject(indexSlide, "mouse"); + this.addAction(indexSlide, "move", json.data[indexSlide].object[1].id, "onClick", mouseX, mouseY, speed); + this.addAction(indexSlide, "appear", json.data[indexSlide].object[0].id, "afterPrevious"); + }; + + /* + * Object factory. + * Add a new Object in the slide idSlide. + * @param int idSlide + * @param string type + * Other params can be specified depending on the object's type. + */ + this.addObject = function (idSlide, type) { + var object = { + "type": type + }; + switch (type.toLowerCase()) { + case "background": + object.id = arguments[2] + json.data[idSlide].object.length; + object.img = arguments[3] || ""; + break; + case "mouse": + object.id = "mouse-cursor"; + break; + case "tooltip": + /* + * TODO: we'll need a more robust unique name + * when we start actually using this. + */ + object.id = "s" + idSlide + "-o" + json.data[idSlide].object.length; + object.text = arguments[2] || ""; + object.color = arguments[3] || null; + object.width = arguments[4] || ""; + json.data[idSlide].object.push(object); + var objectLength = json.data[idSlide].object.length; + var last = json.data[idSlide].object[objectLength-1]; + json.data[idSlide].object[objectLength-1] = + json.data[idSlide].object[objectLength-2]; + json.data[idSlide].object[objectLength-2] = last; + break; + } + if(type.toLowerCase() != "tooltip"){ + json.data[idSlide].object.push(object); + } + }; + + /* + * Action factory. + * Add a new Action in the slide idSlide whose target is the id of an object. + * Three types of trigger : "withPrevious", "afterPrevious", "onClick". + * @param int idSlide + * @param string type + * @param string target + * @param string trigger + * Other params can be specified depending on the object's type. + */ + this.addAction = function (idSlide, type, target, trigger) { + var action = { + "id": generateUniqueActionId(), + "type": type, + "target": target, + "trigger": trigger + }; + switch (type.toLowerCase()) { + case "appear": + action.abs = arguments[4] || 0.0; + action.ord = arguments[5] || 0.0; + action.duration = arguments[6] || 0; + break; + case "disappear": + action.duration = arguments[4] || 0; + break; + case "move": + action.finalAbs = arguments[4] || 0.0; + action.finalOrd = arguments[5] || 0.0; + action.speed = arguments[6] || 0; + break; + } + json.data[idSlide].action.push(action); + }; + + this.editMouse = function (idSlide, idAction, mouseX, mouseY) { + json.data[idSlide].action[idAction].finalAbs = mouseX; + json.data[idSlide].action[idAction].finalOrd = mouseY; + }; + + /* + * Sets a title for the presentation. + * @param String title Title to set. + */ + this.setTitle = function (title) { + json.metaData.title = title; + }; + + /* + * Sets an annotation for the presentation. + * @param String annotation Annotation to set. + */ + this.setAnnotation = function (annotation) { + json.metaData.annotation = annotation; + }; + + /* + * Inverts the two slides (their positions on the table). + * @param int idSlide1 Index of the first slide. + * @param int idSlide2 Index of the second slide. + */ + this.invertSlides = function (idSlide1, idSlide2) { + var tmp = json.data[idSlide1]; + json.data[idSlide1] = json.data[idSlide2]; + json.data[idSlide2] = tmp; + }; + + /* + * Inverts the two actions (their positions on the table). + * @param int idSlide + * @param int idAction1 + * @param int idAction2 + */ + this.invertActions = function (idSlide, idAction1, idAction2) { + var tmp = json.data[idSlide].action[idAction1]; + json.data[idSlide].action[idAction1] = json.data[idSlide].action[idAction2]; + json.data[idSlide].action[idAction2] = tmp; + }; + + /* + * Returns the actions on the specified slide. + * @returns {Array} + */ + this.getActionList = function (idSlide) { + return json.data[idSlide].action; + }; + + /* + * Catches all the objects of the presentation + * @returns {Array} List of objects of the presentation + */ + this.getObjectList = function () { + var objectList = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + var indexObject = 0; + while (json.data[indexSlide].object[indexObject]) { + objectList.push(json.data[indexSlide].object[indexObject]); + indexObject++; + } + indexSlide++; + } + return objectList; + }; + + /* + * Returns an array containing all the background images. + * @returns {Array} List of background images. + */ + this.getImageList = function () { + var list = new Array(); + var indexSlide = 0; + while (json.data[indexSlide]) { + list.push(json.data[indexSlide].object[0].img); + indexSlide++; + } + ; + return list; + }; + + /* + * Returns an object containing the id of the first background. + * @returns {string} Id of the first background. + */ + this.getInitialBackground = function () { + return json.data[0].object[0].id; + }; + + /* + * Returns an object containing the initial mouse position. + * @returns {object} Initial position of mouse. + */ + this.getInitialMousePos = function () { + var pos = {}; + pos.x = json.data[0].action[0].finalAbs; + pos.y = json.data[0].action[0].finalOrd; + return pos; + }; + + /* + * Removes the slide at the specified index. + * @param {int} idSlide + */ + this.removeSlide = function (idSlide) { + json.data.splice(idSlide, 1); + }; + + /* + * Removes the action at the specified slide. + * @param {int} idSlide + * @param {int} idAction + */ + this.removeAction = function (idSlide, idAction) { + json.data[idSlide].action.splice(idAction, 1); + }; + + /* + * Removes the specified object from the slide. + * Also removes all the actions attached to this object. + * @param {int} idSlide + * @param {int} idObject + */ + this.removeObject = function (idSlide, idObject) { + var removed = json.data[idSlide].object.splice(idObject, 1); + for (var i = 0; i < json.data.length; i++) { + var j = 0; + while (json.data[i].action[j]) { + if (json.data[i].action[j].target === removed.id) { + json.data[i].action.splice(j, 1); + } else { + j++; + } + } + } + }; + + /* + * @returns {String} + */ + this.getJson = function () { + return JSON.stringify(json, null, ' '); + }; + + /* + * @returns {String} returns the index for the next slide. + */ + this.getNbSlide = function () { + return json.data.length; + }; + + /* + * @return {object} returns the object identified by idSlide + */ + this.getSlide = function (idSlide) { + return json.data[idSlide]; + }; + + /* + * Sets the size of images for the generated presentation. + * The parameters can be null : it means there are no + * requirement for this dimension. + * @param {int} width New width for the generated images. + * @param {int} height New height for the generated images. + */ + this.setImageSizeRequirements = function (width, height) { + json.metaData.imageWidth = width; + json.metaData.imageHeight = height; + }; + + /* + * Gets the width of images for the generated presentation. + * @return {int or null} Width of generated images. + */ + this.getImageWidth = function () { + return json.metaData.imageWidth; + }; + + /* + * Gets the height of images for the generated presentation. + * @return {int or null} Height of generated images. + */ + this.getImageHeight = function () { + return json.metaData.imageHeight; + }; + + /* + * Gets a background image (no one in particular, the first met). + * @return {string} The name of a background image. + */ + this.getABackgroundImage = function () { + for (var i = 0; i < json.data.length; i++) { + for (var j = 0; j < json.data[i].object.length; j++) { + if (json.data[i].object[j].type === "background") { + return json.data[i].object[j].img; + } + } + } + return null; + }; + }; + + /* public API */ + + self.version = "0.0.1"; + + self.createScreencastGenerator = function createScreencastGenerator() { + return new DahuScreencastGenerator(); + }; + + self.createScreencastModel = function createScreencastModel() { + return new DahuScreencastModel(); + }; + + self.createScreencastExecutableModel = function createScreencastExecutableModel() { + return new DahuScreencastExecutableModel(); + }; + + self.createScreencastGeneratedModel = function createScreencastGeneratedModel() { + return new DahuScreencastGeneratedModel(); + }; + + return self; + })(); + + window.dahuapp = dahuapp; + +})(window, jQuery); \ No newline at end of file diff --git a/TP/TP01/P08/dahuapp.viewer.css b/TP/TP01/P08/dahuapp.viewer.css new file mode 100644 index 0000000000000000000000000000000000000000..ea934576dad6ca9263a6163de58f5fe4534d1f0b --- /dev/null +++ b/TP/TP01/P08/dahuapp.viewer.css @@ -0,0 +1,25 @@ +.object-list { + position: absolute; + margin: 0px; + padding: 0px; +} + +.mouse-cursor { + position: absolute; +} + +.control { + position: relative; +} + +.background { + position: absolute; +} + +.tooltip { + position: absolute; + width: 100px; + padding: 4px; + margin: 2px; + border: 2px black solid; +} \ No newline at end of file diff --git a/TP/TP01/P08/dahuapp.viewer.js b/TP/TP01/P08/dahuapp.viewer.js new file mode 100644 index 0000000000000000000000000000000000000000..12ad03b2cdc503a8fd6ff3f5fdc2a74edbb36edb --- /dev/null +++ b/TP/TP01/P08/dahuapp.viewer.js @@ -0,0 +1,456 @@ +"use strict"; + +/** + * Dahuapp viewer module. + * + * @param dahuapp dahuapp object to augment with module. + * @param $ jQuery + * @returns dahuapp extended with viewer module. + */ + +(function(dahuapp, $) { + var viewer = (function() { + + var self = {}; + + var DahuViewerModel = function(select, getParams) { + + /* Private API */ + + var json = null; + var selector = select; + var parseAutoOption = function(name, defaultValue) { + var res = getParams[name]; + if (res == null) { + if (name == 'auto') { + return false; + } else { + return parseAutoOption('auto', defaultValue); + } + } + if (res.toLowerCase() === 'false') { + return false; + } + res = parseInt(res); + if (isNaN(res)) { + // e.g. ?autoplay or ?autoplay=true + return defaultValue; + } + return res; + } + + /* Whether to wait for "next" event between actions */ + var autoPlay = parseAutoOption('autoplay', 5000); + /* Whether to wait for "next" event on page load */ + var autoStart = parseAutoOption('autostart', 5000); + /* Whether to loop back to start at the end of presentation */ + var autoLoop = parseAutoOption('autoloop', 5000); + + var events = (function() { + var self = {}; + /* + * Creates a generic event. + */ + var createEvent = function() { + var callbacks = $.Callbacks(); + return { + publish: callbacks.fire, + subscribe: callbacks.add, + unsubscribe: callbacks.remove, + unsubscribeAll: callbacks.empty + }; + }; + /* + * Called when the button next is pressed. + */ + self.onNext = createEvent(); + /* + * Called when the button previous is pressed. + */ + self.onPrevious = createEvent(); + /* + * Called when an action is over. + */ + self.onActionOver = createEvent(); + /* + * Called when an action starts. + */ + self.onActionStart = createEvent(); + /* + * Called when at least one action was running and has finished. + */ + self.onAllActionFinish = createEvent(); + + return self; + })(); + + /* + * Variables used like index for methodes subscribed. + */ + var currentAction = 0; /* Action currently running */ + var nextAction = 0; /* Action to execute on 'Next' click */ + var nbActionsRunning = 0; + var previousAnchor = -1; /* Last entered anchor, only used in + * case the 'onhashchange' event is + * not supported by the web browser */ + + /* + * Functions to reinitialise running actions and subscribed + * callbacks (reinitialise is called once without stopping + * all the actions, so the two functions are separated). + */ + var stopAllActions = function() { + $(selector + " .object-list").children().stop(true, true); + reinitialiseCallbackLists(); + nbActionsRunning = 0; + }; + var reinitialiseCallbackLists = function() { + events.onActionStart.unsubscribeAll(); + events.onActionStart.subscribe(onActionStartEventHandler); + events.onAllActionFinish.unsubscribeAll(); + }; + + /* + * Timer used to program onNext event in autoplay mode. + */ + var playTimer = 0; + + /* + * Function used when an "onNextEvent" event is caught. + */ + var onNextEventHandler = function() { + /* + * If the user pressed "next" before an autoplay event + * is triggered, it replaces the autoplay event, hence + * cancels it: + */ + window.clearTimeout(playTimer); + + enterAnimationMode(); + stopAllActions(); + var tmpAction = nextAction; + var onlyWithPrevious = true; + nextAction++; + currentAction = nextAction; + while (json.action[currentAction] && onlyWithPrevious) { + switch (json.action[currentAction].trigger) { + case 'onClick': + nextAction = currentAction; + onlyWithPrevious = false; + break; + case 'withPrevious': + var tmp = currentAction; + /* + * We can't directly pass 'execute' as callback because we + * allow the 'execute' function to reference a property of the + * object (by using 'this.property') so we have to call the + * function in the containing object to make that available + */ + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + while (json.action[nextAction] && json.action[nextAction].trigger !== 'onClick') { + nextAction++; + } + onlyWithPrevious = false; + break; + } + currentAction++; + } + if (json.action[tmpAction]) { + launch(json.action[tmpAction]); + } + if (nextAction > json.action.length) { + nextAction = json.action.length; + } + }; + + /* + * Function used when an "onPreviousEvent" event is caught. + */ + var onPreviousEventHandler = function() { + stopAllActions(); + currentAction = nextAction - 1; + while (json.action[currentAction] && json.action[currentAction].trigger !== 'onClick') { + launchReverse(json.action[currentAction]); + currentAction--; + } + /* currentAction = -1 means that it's the beginning */ + if (currentAction > -1) { + launchReverse(json.action[currentAction]); + } + if (currentAction < 0) { + currentAction = 0; + } + nextAction = currentAction; + }; + + /* + * Function used when an "onActionOverEvent" event is caught. + */ + var onActionOverEventHandler = function() { + nbActionsRunning--; + if (nbActionsRunning === 0) { + events.onAllActionFinish.publish(events, selector); + reinitialiseCallbackLists(); + while (json.action[currentAction]) { + switch (json.action[currentAction].trigger) { + case 'onClick': + leaveAnimationMode(); + if (autoPlay && nbActionsRunning === 0) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoPlay); + } + return; + case 'withPrevious': + var tmp = currentAction; + events.onActionStart.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + break; + case 'afterPrevious': + var tmp = currentAction; + events.onAllActionFinish.subscribe(function(events, selector) { + json.action[tmp].execute(events, selector); + }); + currentAction++; + return; + } + currentAction++; + + } + if (autoLoop && nbActionsRunning === 0) { + setTimeout(function () { + resetPresentation(); + startPresentationMaybe(); + }, autoLoop); + } + } + leaveAnimationMode(); + }; + + /* + * Function used when an "onActionStartEvent" event is caught. + */ + var onActionStartEventHandler = function() { + nbActionsRunning++; + }; + + /* + * Enter and leave "animation" mode. The viewer is in + * animation mode when something is going on without human + * interaction (i.e. executing actions before the next + * "onClick"). + */ + var enterAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').hide(); + $(selector + ' .mouse-cursor-normal').show(); + }; + + var leaveAnimationMode = function () { + $(selector + ' .mouse-cursor-pause').show(); + $(selector + ' .mouse-cursor-normal').hide(); + }; + + /* + * Function used to perform actions. + */ + var launch = function(action) { + action.execute(events, selector); + }; + var launchReverse = function(action) { + action.executeReverse(selector); + }; + + /* + * The two following methods each returns an array containing the + * actions to execute to reach the given anchor (respectively + * forward or backwards). + * + * If the given anchor matches none of the actions, then an empty + * array is returned. + */ + var getActionsToJumpForward = function(anchor) { + var actions = new Array(); + for (var i = nextAction; i < json.action.length; i++) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + if (json.action[i].id == anchor) { + return actions; + } else { + actions.push(json.action[i]); + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + var getActionsToJumpBackwards = function(anchor) { + var actions = new Array(); + for (var i = nextAction - 1; i >= 0; i--) { + // '==' and not '===' because we compare indifferently a + // number or a string or anything else + actions.push(json.action[i]); + if (json.action[i].id == anchor) { + return actions; + } + } + // Here, the anchor has not been found during the action scan + return null; + }; + + /* + * Updates the position of the presentation depending on the + * given anchor (next action wanted). + */ + var jumpToAnchor = function(anchor) { + if (anchor !== '') { + stopAllActions(); + if (anchor > nextAction) { + // forward + var actions = getActionsToJumpForward(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeImmediately(selector); + } + nextAction += actions.length; + } else { + // backwards + var actions = getActionsToJumpBackwards(anchor); + for (var i = 0; i < actions.length; i++) { + actions[i].executeReverse(selector); + } + nextAction -= actions.length; + } + } + }; + + var resetPresentation = function() { + window.clearTimeout(playTimer); + + currentAction = 0; + nextAction = 0; + nbActionsRunning = 0; + + /* + * At the beginning, the visible image is the first one of the presentation + */ + $(selector + " .object-list").children().hide(); + + $(selector + " ." + json.metaData.initialBackgroundId).show(); + + $(selector + " .mouse-cursor").css({ + 'top': (json.metaData.initialMouseY * json.metaData.imageHeight) + "px", + 'left': (json.metaData.initialMouseX * json.metaData.imageWidth) + "px" + }); + + $(selector + " .mouse-cursor").show(); + } + + var startPresentationMaybe = function() { + if (autoStart) { + playTimer = setTimeout(function () { + events.onNext.publish(); + }, autoStart); + } + } + + /* Public API */ + + this.loadUrl = function(url) { + var dataJson; + $.ajax({ + 'async': false, + 'global': false, + 'url': url, + 'dataType': "json", + 'success': function(data) { + dataJson = data; + } + }); + + load(dataJson); + }; + + this.load = function(dataJson) { + /* Transforms data JSON to executable functions for actions */ + var execModel = dahuapp.createScreencastExecutableModel(); + execModel.loadJson(dataJson); + json = execModel.getJson(); + }; + + this.start = function() { + + /* + * Subscription of methods to their events. + */ + events.onNext.subscribe(onNextEventHandler); + events.onPrevious.subscribe(onPreviousEventHandler); + events.onActionOver.subscribe(onActionOverEventHandler); + events.onActionStart.subscribe(onActionStartEventHandler); + + resetPresentation(); + + /* + * If an anchor has been specified, we place the presentation + * in the right position. + */ + jumpToAnchor(window.location.hash.substring(1)); + + /* + * If the anchor changes during the presentation, then the + * presentation is updated + */ + if ("onhashchange" in window) { + // event supported + window.onhashchange = function () { + jumpToAnchor(window.location.hash.substring(1)); + }; + } else { + // event not supported : periodical check + window.setInterval(function () { + if (window.location.hash.substring(1) !== previousAnchor) { + previousAnchor = window.location.hash.substring(1); + jumpToAnchor(window.location.hash.substring(1)); + } + }, 100); + } + + /* + * A click on the "next" button publishes a nextSlide event + */ + $(selector + " .next").click(function() { + events.onNext.publish(); + }); + + /* + * A click on the "previous" button publishes a previousSlide event + */ + $(selector + " .previous").click(function() { + events.onPrevious.publish(); + }); + + /* + * Everything is ready, show the presentation + * (hidden with style="display: none" from HTML). + */ + $("#loading").hide(); + $(selector + " .object-list").show(); + startPresentationMaybe(); + }; + }; + + self.createDahuViewer = function(selector, getParams) { + return new DahuViewerModel(selector, getParams); + }; + + return self; + })(); + + dahuapp.viewer = viewer; +})(dahuapp || {}, jQuery); diff --git a/TP/TP01/P08/img/069aaa71-3b56-79ea-e75e-63811f68fe4a.png b/TP/TP01/P08/img/069aaa71-3b56-79ea-e75e-63811f68fe4a.png new file mode 100644 index 0000000000000000000000000000000000000000..836c7ace6f4e18cedb4f2161b38dfa66dc622ab6 Binary files /dev/null and b/TP/TP01/P08/img/069aaa71-3b56-79ea-e75e-63811f68fe4a.png differ diff --git a/TP/TP01/P08/img/0af5556e-a441-f350-4097-3555d13216ed.png b/TP/TP01/P08/img/0af5556e-a441-f350-4097-3555d13216ed.png new file mode 100644 index 0000000000000000000000000000000000000000..3106a14e1c607e104bebf4b60cd5959019f06f24 Binary files /dev/null and b/TP/TP01/P08/img/0af5556e-a441-f350-4097-3555d13216ed.png differ diff --git a/TP/TP01/P08/img/15382a62-0ab0-a407-3084-eaf9dcfbf5ff.png b/TP/TP01/P08/img/15382a62-0ab0-a407-3084-eaf9dcfbf5ff.png new file mode 100644 index 0000000000000000000000000000000000000000..c7e9ebf43a61b167804e6292c15ae838d9a07606 Binary files /dev/null and b/TP/TP01/P08/img/15382a62-0ab0-a407-3084-eaf9dcfbf5ff.png differ diff --git a/TP/TP01/P08/img/236a104c-cb6b-160f-f8ce-1a7f1ee05074.png b/TP/TP01/P08/img/236a104c-cb6b-160f-f8ce-1a7f1ee05074.png new file mode 100644 index 0000000000000000000000000000000000000000..998f2d5196fcdafc8ff3ecfff270938bcab6ce35 Binary files /dev/null and b/TP/TP01/P08/img/236a104c-cb6b-160f-f8ce-1a7f1ee05074.png differ diff --git a/TP/TP01/P08/img/2c60718e-61a6-59a8-8af1-cd0d41b5e373.png b/TP/TP01/P08/img/2c60718e-61a6-59a8-8af1-cd0d41b5e373.png new file mode 100644 index 0000000000000000000000000000000000000000..eb2eef94da51c1ff6a298c3d72e6cc5c04db5b4a Binary files /dev/null and b/TP/TP01/P08/img/2c60718e-61a6-59a8-8af1-cd0d41b5e373.png differ diff --git a/TP/TP01/P08/img/43eedad3-474b-b7e5-97fd-847e21828079.png b/TP/TP01/P08/img/43eedad3-474b-b7e5-97fd-847e21828079.png new file mode 100644 index 0000000000000000000000000000000000000000..d073fc6916a23c28b311b8ad601b91849f940a28 Binary files /dev/null and b/TP/TP01/P08/img/43eedad3-474b-b7e5-97fd-847e21828079.png differ diff --git a/TP/TP01/P08/img/94181b34-2c0b-9cbe-4c87-1f0088fbca9b.png b/TP/TP01/P08/img/94181b34-2c0b-9cbe-4c87-1f0088fbca9b.png new file mode 100644 index 0000000000000000000000000000000000000000..ac108c4d00008d492b172860b6be43491744ca2c Binary files /dev/null and b/TP/TP01/P08/img/94181b34-2c0b-9cbe-4c87-1f0088fbca9b.png differ diff --git a/TP/TP01/P08/img/9b9bbd73-13f7-d649-3df8-0a86d795991b.png b/TP/TP01/P08/img/9b9bbd73-13f7-d649-3df8-0a86d795991b.png new file mode 100644 index 0000000000000000000000000000000000000000..f5f7cdfac3a735646ae6d4c8cf4db14ed3bf7500 Binary files /dev/null and b/TP/TP01/P08/img/9b9bbd73-13f7-d649-3df8-0a86d795991b.png differ diff --git a/TP/TP01/P08/img/9e01253b-aeaf-d9a3-ae09-f315bda59ae5.png b/TP/TP01/P08/img/9e01253b-aeaf-d9a3-ae09-f315bda59ae5.png new file mode 100644 index 0000000000000000000000000000000000000000..baeda64365b64074907e342d9300f6cd182f13b3 Binary files /dev/null and b/TP/TP01/P08/img/9e01253b-aeaf-d9a3-ae09-f315bda59ae5.png differ diff --git a/TP/TP01/P08/img/a7c8540c-fc03-44ff-1f9f-0b85413ce823.png b/TP/TP01/P08/img/a7c8540c-fc03-44ff-1f9f-0b85413ce823.png new file mode 100644 index 0000000000000000000000000000000000000000..f8038000e7fa95d83294eb4e37c8f77f6d6e8c61 Binary files /dev/null and b/TP/TP01/P08/img/a7c8540c-fc03-44ff-1f9f-0b85413ce823.png differ diff --git a/TP/TP01/P08/img/a9008f63-c085-525e-9221-5fc5e475a0a5.png b/TP/TP01/P08/img/a9008f63-c085-525e-9221-5fc5e475a0a5.png new file mode 100644 index 0000000000000000000000000000000000000000..e7c9708b1cf4adfaa41dde46998913c573286294 Binary files /dev/null and b/TP/TP01/P08/img/a9008f63-c085-525e-9221-5fc5e475a0a5.png differ diff --git a/TP/TP01/P08/img/b985855c-63b1-6f17-4017-7110897dc1ab.png b/TP/TP01/P08/img/b985855c-63b1-6f17-4017-7110897dc1ab.png new file mode 100644 index 0000000000000000000000000000000000000000..fa041feb8e4ad0241c7238afef4bc58a6c45cf4d Binary files /dev/null and b/TP/TP01/P08/img/b985855c-63b1-6f17-4017-7110897dc1ab.png differ diff --git a/TP/TP01/P08/img/be074647-825d-d17e-f05b-8e7d48446660.png b/TP/TP01/P08/img/be074647-825d-d17e-f05b-8e7d48446660.png new file mode 100644 index 0000000000000000000000000000000000000000..127dee310f88085f0c41664a5fdcd0782a8b6a17 Binary files /dev/null and b/TP/TP01/P08/img/be074647-825d-d17e-f05b-8e7d48446660.png differ diff --git a/TP/TP01/P08/img/c82d39c7-94bb-d6ec-f21a-53f6606b7882.png b/TP/TP01/P08/img/c82d39c7-94bb-d6ec-f21a-53f6606b7882.png new file mode 100644 index 0000000000000000000000000000000000000000..66bdf40f5ad1e32c5b8519a3ad33c54e88d6a0d2 Binary files /dev/null and b/TP/TP01/P08/img/c82d39c7-94bb-d6ec-f21a-53f6606b7882.png differ diff --git a/TP/TP01/P08/img/cursor-pause.png b/TP/TP01/P08/img/cursor-pause.png new file mode 100644 index 0000000000000000000000000000000000000000..9c93cc142f4326a188eafc3c0fe96f2975dcab0c Binary files /dev/null and b/TP/TP01/P08/img/cursor-pause.png differ diff --git a/TP/TP01/P08/img/cursor.png b/TP/TP01/P08/img/cursor.png new file mode 100644 index 0000000000000000000000000000000000000000..5b4a20e63078ce18bb11a4e601a1994b261522ef Binary files /dev/null and b/TP/TP01/P08/img/cursor.png differ diff --git a/TP/TP01/P08/img/e56d6655-5a00-524d-53f5-0b43e69122e0.png b/TP/TP01/P08/img/e56d6655-5a00-524d-53f5-0b43e69122e0.png new file mode 100644 index 0000000000000000000000000000000000000000..d9a69c031ffa14beee6628ca7060c0a08de6ec7b Binary files /dev/null and b/TP/TP01/P08/img/e56d6655-5a00-524d-53f5-0b43e69122e0.png differ diff --git a/TP/TP01/P08/img/fa839127-dceb-6619-d9d7-0c60b4b4601d.png b/TP/TP01/P08/img/fa839127-dceb-6619-d9d7-0c60b4b4601d.png new file mode 100644 index 0000000000000000000000000000000000000000..24c3c23bae21b63ddc30cb30eb79c15d20c271c6 Binary files /dev/null and b/TP/TP01/P08/img/fa839127-dceb-6619-d9d7-0c60b4b4601d.png differ diff --git a/TP/TP01/P08/index.html b/TP/TP01/P08/index.html new file mode 100644 index 0000000000000000000000000000000000000000..055d67a0c5c9ccfbe6b1d5f767b255a73532d092 --- /dev/null +++ b/TP/TP01/P08/index.html @@ -0,0 +1,497 @@ +<!DOCTYPE html> + +<html lang="en"> + +<head> +<title>Dahu Presentation +</title> +<meta charset="utf-8"> +<script src="http://code.jquery.com/jquery-1.9.1.min.js" type="text/javascript"> +</script> +<script src="parse-search.js" type="text/javascript"> +</script> + +<link rel="stylesheet" href="dahuapp.viewer.css"><style>.s0-o2{background-color: #FFFFDD;width: 240px} +.s1-o2{background-color: #FFFFDD;width: 240px} +.s2-o2{background-color: #FFFFDD;width: 240px} +.s3-o2{background-color: #FFFFDD;width: 240px} +.s4-o2{background-color: #FFFFDD;width: 240px} +.s6-o2{background-color: #FFFFDD;width: 240px} +.s7-o2{background-color: #FFFFDD;width: 240px} +.s8-o2{background-color: #FFFFDD;width: 240px} +.s10-o2{background-color: #FFFFDD;width: 240px} +.s11-o2{background-color: #FFFFDD;width: 240px} +.s12-o2{background-color: #FFFFDD;width: 240px} +.s13-o2{background-color: #FFFFDD;width: 240px} +.s14-o2{background-color: #FFFFDD;width: 240px} +</style> +</head> + +<body> + +<div id="my-dahu-presentation"> + +<div id="loading">Loading presentation... +</div> + +<div class="object-list" style="display: none"> +<img src="img/43eedad3-474b-b7e5-97fd-847e21828079.png" alt="img/43eedad3-474b-b7e5-97fd-847e21828079.png" class="background 43eedad3-474b-b7e5-97fd-847e218280790"> + +<div class="tooltip s0-o2">Nous prenons le modèle du pendule inversé réalisé à la fin de la séance précédente comme point de départ. +</div> +<img src="img/2c60718e-61a6-59a8-8af1-cd0d41b5e373.png" alt="img/2c60718e-61a6-59a8-8af1-cd0d41b5e373.png" class="background 2c60718e-61a6-59a8-8af1-cd0d41b5e3730"> + +<div class="tooltip s1-o2">Sélectionner l'ongle Ports and Subsystems dans la boite à outils Simulink. +</div> +<img src="img/b985855c-63b1-6f17-4017-7110897dc1ab.png" alt="img/b985855c-63b1-6f17-4017-7110897dc1ab.png" class="background b985855c-63b1-6f17-4017-7110897dc1ab0"> + +<div class="tooltip s2-o2">Sélectionner le bloc SubSystem. +</div> +<img src="img/c82d39c7-94bb-d6ec-f21a-53f6606b7882.png" alt="img/c82d39c7-94bb-d6ec-f21a-53f6606b7882.png" class="background c82d39c7-94bb-d6ec-f21a-53f6606b78820"> + +<div class="tooltip s3-o2">Déposer un bloc SubSystem dans votre modèle. Noter que celui-ci comporte une entrée et une sortie. +</div> +<img src="img/0af5556e-a441-f350-4097-3555d13216ed.png" alt="img/0af5556e-a441-f350-4097-3555d13216ed.png" class="background 0af5556e-a441-f350-4097-3555d13216ed0"> + +<div class="tooltip s4-o2">Découper le modèle en deux parties : le système et les afficheurs. +</div> +<img src="img/be074647-825d-d17e-f05b-8e7d48446660.png" alt="img/be074647-825d-d17e-f05b-8e7d48446660.png" class="background be074647-825d-d17e-f05b-8e7d484466600"> +<img src="img/94181b34-2c0b-9cbe-4c87-1f0088fbca9b.png" alt="img/94181b34-2c0b-9cbe-4c87-1f0088fbca9b.png" class="background 94181b34-2c0b-9cbe-4c87-1f0088fbca9b0"> + +<div class="tooltip s6-o2">Découper la partie système que nous allons déplacer dans le bloc SubSystem. +</div> +<img src="img/9e01253b-aeaf-d9a3-ae09-f315bda59ae5.png" alt="img/9e01253b-aeaf-d9a3-ae09-f315bda59ae5.png" class="background 9e01253b-aeaf-d9a3-ae09-f315bda59ae50"> + +<div class="tooltip s7-o2">Ouvrir le bloc SubSystem par un double clic. +</div> +<img src="img/fa839127-dceb-6619-d9d7-0c60b4b4601d.png" alt="img/fa839127-dceb-6619-d9d7-0c60b4b4601d.png" class="background fa839127-dceb-6619-d9d7-0c60b4b4601d0"> + +<div class="tooltip s8-o2">Coller le système découpé dans une étape précédente. +</div> +<img src="img/236a104c-cb6b-160f-f8ce-1a7f1ee05074.png" alt="img/236a104c-cb6b-160f-f8ce-1a7f1ee05074.png" class="background 236a104c-cb6b-160f-f8ce-1a7f1ee050740"> +<img src="img/a9008f63-c085-525e-9221-5fc5e475a0a5.png" alt="img/a9008f63-c085-525e-9221-5fc5e475a0a5.png" class="background a9008f63-c085-525e-9221-5fc5e475a0a50"> + +<div class="tooltip s10-o2">Supprimer le signal entre le port d'entrée et le port de sortie. +</div> +<img src="img/a7c8540c-fc03-44ff-1f9f-0b85413ce823.png" alt="img/a7c8540c-fc03-44ff-1f9f-0b85413ce823.png" class="background a7c8540c-fc03-44ff-1f9f-0b85413ce8230"> + +<div class="tooltip s11-o2">Connecter le port de sortie avec le signal portant l'angle alpha. +</div> +<img src="img/15382a62-0ab0-a407-3084-eaf9dcfbf5ff.png" alt="img/15382a62-0ab0-a407-3084-eaf9dcfbf5ff.png" class="background 15382a62-0ab0-a407-3084-eaf9dcfbf5ff0"> + +<div class="tooltip s12-o2">Supprimer le port d'entrée. +</div> +<img src="img/9b9bbd73-13f7-d649-3df8-0a86d795991b.png" alt="img/9b9bbd73-13f7-d649-3df8-0a86d795991b.png" class="background 9b9bbd73-13f7-d649-3df8-0a86d795991b0"> + +<div class="tooltip s13-o2">Aller à la racine du modèle hiérarchique. +</div> +<img src="img/069aaa71-3b56-79ea-e75e-63811f68fe4a.png" alt="img/069aaa71-3b56-79ea-e75e-63811f68fe4a.png" class="background 069aaa71-3b56-79ea-e75e-63811f68fe4a0"> + +<div class="tooltip s14-o2">Connecter la sortie du bloc sur les afficheurs. +</div> + +<div class="mouse-cursor"> +<img src="img/cursor.png" alt="img/cursor.png" class="mouse-cursor-normal"> +<img src="img/cursor-pause.png" alt="img/cursor-pause.png" style="display: none" class="mouse-cursor-pause"> +</div> +</div> + +<div class="control" style="top: 616px;"> +<button class="previous">Previous +</button> +<button class="next">Next +</button> +</div> +</div> +<script src="dahuapp.js" type="text/javascript"> +</script> +<script src="dahuapp.viewer.js" type="text/javascript"> +</script> +<script type="text/javascript">(function($) { + var myPresentation = dahuapp.viewer.createDahuViewer("#my-dahu-presentation", window.getParams); + myPresentation.load({ + "metaData": { + "imageWidth": 800, + "imageHeight": 600, + "initialBackgroundId": "43eedad3-474b-b7e5-97fd-847e218280790", + "initialMouseX": 0.36944444444444446, + "initialMouseY": 0.34 + }, + "action": [ + { + "id": "33", + "type": "appear", + "target": "s0-o2", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 400 + }, + { + "id": "3", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.7680555555555556, + "finalOrd": 0.3411111111111111, + "speed": 0.8 + }, + { + "id": "4", + "type": "appear", + "target": "2c60718e-61a6-59a8-8af1-cd0d41b5e3730", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "34", + "type": "appear", + "target": "s1-o2", + "trigger": "afterPrevious", + "abs": 0.39166666666666666, + "ord": 0.16, + "duration": 400 + }, + { + "id": "5", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.8701388888888889, + "finalOrd": 0.48, + "speed": 0.8 + }, + { + "id": "6", + "type": "appear", + "target": "b985855c-63b1-6f17-4017-7110897dc1ab0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "35", + "type": "appear", + "target": "s2-o2", + "trigger": "afterPrevious", + "abs": 0.38666666666666666, + "ord": 0.2275, + "duration": 400 + }, + { + "id": "7", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3076388888888889, + "finalOrd": 0.6455555555555555, + "speed": 0.8 + }, + { + "id": "8", + "type": "appear", + "target": "c82d39c7-94bb-d6ec-f21a-53f6606b78820", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "36", + "type": "appear", + "target": "s3-o2", + "trigger": "afterPrevious", + "abs": 0.32166666666666666, + "ord": 0.26125, + "duration": 400 + }, + { + "id": "9", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3611111111111111, + "finalOrd": 0.43, + "speed": 0.8 + }, + { + "id": "10", + "type": "appear", + "target": "0af5556e-a441-f350-4097-3555d13216ed0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "37", + "type": "appear", + "target": "s4-o2", + "trigger": "afterPrevious", + "abs": 0.28, + "ord": 0.06125, + "duration": 400 + }, + { + "id": "11", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.27291666666666664, + "finalOrd": 0.4411111111111111, + "speed": 0.8 + }, + { + "id": "12", + "type": "appear", + "target": "be074647-825d-d17e-f05b-8e7d484466600", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "13", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.31180555555555556, + "finalOrd": 0.46111111111111114, + "speed": 0.8 + }, + { + "id": "14", + "type": "appear", + "target": "94181b34-2c0b-9cbe-4c87-1f0088fbca9b0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "38", + "type": "appear", + "target": "s6-o2", + "trigger": "afterPrevious", + "abs": 0.25, + "ord": 0.0775, + "duration": 400 + }, + { + "id": "15", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.29791666666666666, + "finalOrd": 0.6533333333333333, + "speed": 0.8 + }, + { + "id": "16", + "type": "appear", + "target": "9e01253b-aeaf-d9a3-ae09-f315bda59ae50", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "39", + "type": "appear", + "target": "s7-o2", + "trigger": "afterPrevious", + "abs": 0.145, + "ord": 0.31625, + "duration": 400 + }, + { + "id": "17", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3145833333333333, + "finalOrd": 0.12555555555555556, + "speed": 0.8 + }, + { + "id": "18", + "type": "appear", + "target": "fa839127-dceb-6619-d9d7-0c60b4b4601d0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "40", + "type": "appear", + "target": "s8-o2", + "trigger": "afterPrevious", + "abs": 0.15333333333333332, + "ord": 0.24875, + "duration": 400 + }, + { + "id": "19", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.3138888888888889, + "finalOrd": 0.33666666666666667, + "speed": 0.8 + }, + { + "id": "20", + "type": "appear", + "target": "236a104c-cb6b-160f-f8ce-1a7f1ee050740", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "21", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.25069444444444444, + "finalOrd": 0.3322222222222222, + "speed": 0.8 + }, + { + "id": "22", + "type": "appear", + "target": "a9008f63-c085-525e-9221-5fc5e475a0a50", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "41", + "type": "appear", + "target": "s10-o2", + "trigger": "afterPrevious", + "abs": 0.19666666666666666, + "ord": 0.05875, + "duration": 400 + }, + { + "id": "23", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.4097222222222222, + "finalOrd": 0.5422222222222223, + "speed": 0.8 + }, + { + "id": "24", + "type": "appear", + "target": "a7c8540c-fc03-44ff-1f9f-0b85413ce8230", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "42", + "type": "appear", + "target": "s11-o2", + "trigger": "afterPrevious", + "abs": 0.21333333333333335, + "ord": 0.09375, + "duration": 400 + }, + { + "id": "27", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.11875, + "finalOrd": 0.31555555555555553, + "speed": 0.8 + }, + { + "id": "28", + "type": "appear", + "target": "15382a62-0ab0-a407-3084-eaf9dcfbf5ff0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "43", + "type": "appear", + "target": "s12-o2", + "trigger": "afterPrevious", + "abs": 0.16, + "ord": 0.0975, + "duration": 400 + }, + { + "id": "29", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.21944444444444444, + "finalOrd": 0.4066666666666667, + "speed": 0.8 + }, + { + "id": "30", + "type": "appear", + "target": "9b9bbd73-13f7-d649-3df8-0a86d795991b0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "44", + "type": "appear", + "target": "s13-o2", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 400 + }, + { + "id": "31", + "type": "move", + "target": "mouse-cursor", + "trigger": "onClick", + "finalAbs": 0.2701388888888889, + "finalOrd": 0.5422222222222223, + "speed": 0.8 + }, + { + "id": "32", + "type": "appear", + "target": "069aaa71-3b56-79ea-e75e-63811f68fe4a0", + "trigger": "afterPrevious", + "abs": 0, + "ord": 0, + "duration": 0 + }, + { + "id": "45", + "type": "appear", + "target": "s14-o2", + "trigger": "afterPrevious", + "abs": 0.04, + "ord": 0.085, + "duration": 400 + } + ] +}); + myPresentation.start(); +})(jQuery); + +</script> +</body> +</html> \ No newline at end of file diff --git a/TP/TP01/P08/parse-search.js b/TP/TP01/P08/parse-search.js new file mode 100644 index 0000000000000000000000000000000000000000..e7d01c07f6a5d45b9fcabd5d271a8c6cfc5f00e2 --- /dev/null +++ b/TP/TP01/P08/parse-search.js @@ -0,0 +1,14 @@ +// Adapted from http://stackoverflow.com/questions/3234125/creating-array-from-window-location-hash +(function () { + var search = window.location.search.slice(1); + var array = search.split("&"); + + var values, form_data = {}; + + for (var i = 0; i < array.length; i += 1) { + values = array[i].split("="); + form_data[values[0]] = unescape(values[1]); + } + window.getParams = form_data; +}()) + diff --git a/TP/TP01/automatique-sn-tp-01.pdf b/TP/TP01/automatique-sn-tp-01.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e5c57e47edaa5a4fbb70a229b94d879f6e5ca3a2 Binary files /dev/null and b/TP/TP01/automatique-sn-tp-01.pdf differ diff --git a/TP/TP02/TP-2-tp-simulation.pdf b/TP/TP02/TP-2-tp-simulation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..582444f63ed91c2033d86e852549f26ebc61a3ce Binary files /dev/null and b/TP/TP02/TP-2-tp-simulation.pdf differ diff --git a/TP/TP02/pendule_inverse.zip b/TP/TP02/pendule_inverse.zip new file mode 100644 index 0000000000000000000000000000000000000000..0c4bbfe01a509704c9bdb88a962edb8a8a235572 Binary files /dev/null and b/TP/TP02/pendule_inverse.zip differ diff --git a/TP/TP03/TP-3-tp-simulation.pdf b/TP/TP03/TP-3-tp-simulation.pdf new file mode 100644 index 0000000000000000000000000000000000000000..dee8b6b3807d077eb2a6f3ed648810b4fe4ddc0a Binary files /dev/null and b/TP/TP03/TP-3-tp-simulation.pdf differ