|
|
@@ -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 '<div style="padding:5px;height:100%"><a href="/event/'+ d.uid + |
|
|
|
'">' + d.desc + '</a></div>' |
|
|
|
}) |
|
|
|
.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 +")"); |
|
|
|
} |