diff --git a/jm2l/static/js/programme.js b/jm2l/static/js/programme.js index 407a2b9..9bbd6de 100644 --- a/jm2l/static/js/programme.js +++ b/jm2l/static/js/programme.js @@ -1,111 +1,242 @@ -var scheds = {}; - -function example() { - - var taskStatus = {'Stand':'Stand', - 'Table ronde':'Table-ronde', - 'Atelier':'Atelier', - 'Concert':'Concert', - 'Conference':'Conference', - 'Repas':'Repas'} - - d3.json("le-prog-json", function(error, JsonContent) { - if (error) - return console.warn(error); - $.each( JsonContent, - function( EventType, ListEvType ) { - $.each( ListEvType, - function( Day, ListEvent ) { - var placeNames = []; - for ( var i = 0; i < ListEvent.length; i++) { - placeNames.push(ListEvent[i]["placeName"]); - // convert json text to js Date - ListEvent[i]["startDate"] = new Date(ListEvent[i]["startDate"]); - ListEvent[i]["endDate"] = new Date(ListEvent[i]["endDate"]); - } - //placeNames.push("unk") - scheds[EventType+"_"+Day] = new d3.sched("SVG_"+Day) - .taskTypes(placeNames) - .taskStatus(taskStatus) - .tickFormat("%H:%M"); - //scheds[EventType+"_"+Day].timeDomainMode("fit"); - //scheds[EventType+"_"+Day].margin(margin); - scheds[EventType+"_"+Day](ListEvent); - //scheds[EventType+"_"+Day].zoomed(); - scheds[EventType+"_"+Day].redraw("SVG_"+Day, ListEvent) - }); - }); - }); - +var taskStatus = {'Stand':'Stand', + 'Table ronde':'Table-ronde', + 'Atelier':'Atelier', + 'Concert':'Concert', + 'Conference':'Conference', + 'Repas':'Repas'}; +var tickFormat = "%H:%M"; +var margin = { + top : 15, + right : 0, + bottom : 0, + left : 50 +}; +var height = 500; +var width = 730; +var Keys = Array(); +var Salles = Array(); +var Areas = Array(); +var Tasks = Array(); + + +d3.json("le-prog-json", + function(error, json) { + if (error) return console.warn(error); + var Keys = Object.keys(json["all"]) + // Build set of data in memory + for (var k = 0; k < Keys.length; k++) { + Salles[Keys[k]] = Array(); + Areas[Keys[k]] = Array(); + Tasks[Keys[k]] = json["all"][Keys[k]] + // Fix Json to make date objects + Tasks[Keys[k]].forEach(function(d) { + d.startDate = new Date(d.startDate); + d.endDate = new Date(d.endDate); + }) + + // Build the list of Salles and Areas + Tasks[Keys[k]].forEach(function(d) { + Salles[Keys[k]].push( d.placeName ); + Areas[Keys[k]].push( d.status ); + } ) + Salles[Keys[k]] = d3.set(Salles[Keys[k]]).values(); + Areas[Keys[k]] = d3.set(Areas[Keys[k]]).values(); + // Create Controls to Handle user selection + Areas[Keys[k]].forEach(function(TypeArea) { + d3.select("#Schedule_SVG_"+Keys[k]) + .append("input") + .attr("type", "checkbox") + .attr("name", "OptTimetable-"+Keys[k]) + .attr("id", TypeArea+"-"+Keys[k]) + .attr("area", TypeArea) + .style("float", "left") + .style("margin-left", "5px") + .property("checked",true); + + d3.select("#Schedule_SVG_"+Keys[k]) + .append("label") + .attr("for", TypeArea+"-"+Keys[k]) + .style("float", "left") + .style("margin-left", "5px") + .text(TypeArea); + }); + // Create a dedicated SVG for it + svg = d3.select("#Schedule_SVG_"+Keys[k]) + .append("svg") + .attr("id", "TimeTable-"+Keys[k]) + .attr("width", width + margin.right + margin.left) + .attr("height", height + margin.top + margin.bottom) + //.attr("viewBox", "0 0 " + width + " " + height ) + //.attr("preserveAspectRatio", "xMidYMid"); + + svg.append("g") + .attr("class", "xAxis axis"); + + svg.append("g") + .attr("class", "yAxis axis"); + + var chart = svg.append("g") + .attr("class", "timetable"); + + HandleEvents(Keys[k]) + displayit(json["all"][Keys[k]], Salles[Keys[k]], Keys[k]); + } +}); + +var keyFunction = function(d) { + return d.startDate + d.placeName + d.endDate; }; -// Query Programme -example(); - -function changeTimeDomain(timeDomainString) { - this.timeDomainString = timeDomainString; - switch (timeDomainString) { - case "1hr": - format = "%H:%M:%S"; - sched.timeDomain([ d3.time.hour.offset(getEndDate(), -1), getEndDate() ]); - break; - case "3hr": - format = "%H:%M"; - sched.timeDomain([ d3.time.hour.offset(getEndDate(), -3), getEndDate() ]); - break; - - case "6hr": - format = "%H:%M"; - sched.timeDomain([ d3.time.hour.offset(getEndDate(), -6), getEndDate() ]); - break; - - case "1day": - format = "%H:%M"; - sched.timeDomain([ d3.time.day.offset(getEndDate(), -1), getEndDate() ]); - break; - - case "1week": - format = "%a %H:%M"; - sched.timeDomain([ d3.time.day.offset(getEndDate(), -7), getEndDate() ]); - break; - default: - format = "%H:%M" - - } - sched.tickFormat(format); - sched.redraw(tasks); -} - -function getEndDate() { - var lastEndDate = Date.now(); - if (tasks.length > 0) { - lastEndDate = tasks[tasks.length - 1].endDate; - } - - return lastEndDate; +function HandleEvents(Ctrl) { + d3.selectAll("input[name=OptTimetable-"+Ctrl+"]") + .data(Areas[Ctrl]) + .on("change", function(TypeData) { + ArrayChoice = Array() + checked = d3.selectAll("input[name=OptTimetable-"+Ctrl+"]")[0] + .forEach( function(v) + { + if (d3.select(v).node().checked) + ArrayChoice.push(v.attributes['area'].value) + } + ) + area_select = Array() + selection = Tasks[Ctrl].filter(function(v) { + return ArrayChoice.indexOf(v.status)>=0; + }); + if (selection.length) { + selection.forEach(function(d) + { area_select.push( d.placeName ); } + ); + area_select = d3.set(area_select).values(); + displayit(selection, area_select, Ctrl); + d3.select("#TimeTable-"+Ctrl)[0][0].style.opacity = 1; + } else { + d3.select("#TimeTable-"+Ctrl)[0][0].style.opacity = 0; + } + }); } -function addTask() { - - var lastEndDate = getEndDate(); - var taskStatusKeys = Object.keys(taskStatus); - var taskStatusName = taskStatusKeys[Math.floor(Math.random() * taskStatusKeys.length)]; - var taskName = taskNames[Math.floor(Math.random() * taskNames.length)]; - tasks.push({ - "startDate" : d3.time.hour.offset(lastEndDate, Math.ceil(1 * Math.random())), - "endDate" : d3.time.hour.offset(lastEndDate, (Math.ceil(Math.random() * 3)) + 1), - "taskName" : taskName, - "status" : taskStatusName - }); - - changeTimeDomain(timeDomainString); +function displayit(Set_of_Task, Set_of_Area, key) { + // Try to compute time range + Set_of_Task.sort(function(a, b) { + return a.endDate - b.endDate; + }); + timeDomainEnd = Set_of_Task[Set_of_Task.length - 1].endDate; + Set_of_Task.sort(function(a, b) { + return a.startDate - b.startDate; + }); + timeDomainStart = Set_of_Task[0].startDate; + + // Prepare scales + xScale = d3.scale.ordinal() + .domain(Set_of_Area) + .rangeRoundBands([ 0, width ], .1); + + yScale = d3.time.scale() + .domain([ timeDomainStart, timeDomainEnd ]) + .range([ 0, height - margin.top - margin.bottom ]) + .clamp(true); + + xAxis = d3.svg.axis() + .scale(xScale) + .orient("top") + .tickSize(1); + + yAxis = d3.svg.axis() + .scale(yScale) + .orient("left") + .tickFormat(d3.time.format(tickFormat)) + .tickSubdivide(true) + .tickSize(8) + .tickPadding(8); + + var svg = d3.select("#TimeTable-"+key); + + var chart = svg.select(".timetable") + + var content = chart.selectAll("foreignObject") + .data(Set_of_Task, keyFunction); + + content.enter() + .insert("foreignObject",":first-child") + .append("xhtml:div") + .html(function(d) { + return '
' + }) + .transition() + .duration(750); + + content.transition() + .duration(750) + .attr("x", function(d){ + return xScale(d.placeName || "unk"); + }) + .attr("y", function(d){ + return yScale( d.startDate ); + }) + .attr("width", function(d) { + return xScale.rangeBand(); + }) + .attr("height", function(d) { + return (yScale( d.endDate ) - yScale( d.startDate )); + }); + + content.exit() + .transition() + .duration(300) + .style("opacity", 1e-6) + .remove(); + + var rect = chart.selectAll("rect") + .data(Set_of_Task, keyFunction); + + rect.enter() + .insert("rect",":first-child") + .attr("rx", 5) + .attr("ry", 5) + .attr("filter", "url(/img/shadow.svg#dropshadow)") + //.attr("style", "fill:url(/img/shadow.svg#BoxGradient)") + .attr("class", function(d){ + if(taskStatus[d.status] == null) + { return "bar";} + return taskStatus[d.status]; + }) + .transition() + .duration(750) + + + rect.transition() + .duration(750) + .attr("x", function(d){ + return xScale(d.placeName || "unk"); + }) + .attr("y", function(d){ + return yScale( d.startDate )+1; + }) + .attr("width", function(d) { + return xScale.rangeBand(); + }) + .attr("height", function(d) { + return (yScale( d.endDate ) - yScale( d.startDate )-2); + }); + + rect.exit() + .transition() + .duration(300) + .style("opacity", 1e-6) + .remove(); + + svg.select(".yAxis") + .attr("transform", "translate("+ margin.left +","+ margin.top +")") + .transition() + .call(yAxis); - sched.redraw(tasks); -}; + svg.select(".xAxis") + .attr("transform", "translate("+ margin.left +","+ margin.top +")") + .transition() + .call(xAxis); -function removeTask() { - tasks.pop(); - changeTimeDomain(timeDomainString); - sched.redraw(tasks); -}; + chart.attr("transform", "translate("+ margin.left +","+ margin.top +")"); +} \ No newline at end of file diff --git a/jm2l/templates/Public/Programme.mako b/jm2l/templates/Public/Programme.mako index a82dd24..1626bd2 100644 --- a/jm2l/templates/Public/Programme.mako +++ b/jm2l/templates/Public/Programme.mako @@ -14,18 +14,22 @@ TabDisplay = [ height: 65px; } .Conference { - fill:#EEE; - stroke: #ccc; + fill:#f9fde8; + stroke: #a2bc13; } .Concert { fill:#2EE; stroke: #ccc; } .Atelier { - fill: #ddd; - stroke: #ccc; + fill: #faebeb; + stroke: #dc7070; +} +.Table-ronde { + fill: #fff4e5; + stroke: #ff9912; } -.txtsched { +.Repas { fill:#2EE; stroke: #ccc; } @@ -35,7 +39,7 @@ svg { } rect { - fill: #ddd; + stroke-width: 0px; } .axis path, @@ -147,6 +151,6 @@ if Counter==0: ##