Skip to content

Instantly share code, notes, and snippets.

@Saigesp
Last active September 30, 2018 20:19
Show Gist options
  • Save Saigesp/6ff087b5cfc3a3424c58960b895a5455 to your computer and use it in GitHub Desktop.
Save Saigesp/6ff087b5cfc3a3424c58960b895a5455 to your computer and use it in GitHub Desktop.
D3 Time&Expenses
[
{
"project": {
"name": "Proyecto 1",
"manager": {
"name": "JM Royo",
"role": "manager",
"ID": "13"
},
"tasks": [
{
"name": "TFS224",
"description": "Diseñar pantalla de composiciones",
"authors": [
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160510",
"values": "8"
},
{
"key": "20160511",
"values": "4"
},
{
"key": "20160512",
"values": "7.5"
},
{
"key": "20160513",
"values": "4"
}
]
}
]
},
{
"name": "TFS341",
"description": "Gestión de menus basico listado",
"authors": [
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160502",
"values": "8"
}
]
},
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160517",
"values": "2"
}
]
}
]
},
{
"name": "TFS358",
"description": "Gestión de menus basico creación",
"authors": [
{
"name": "Albert Lopez",
"role": "senior",
"values": [
{
"key": "20160502",
"values": "8"
},
{
"key": "20160503",
"values": "8"
},
{
"key": "20160504",
"values": "6"
},
{
"key": "20160505",
"values": "8"
},
{
"key": "20160506",
"values": "8"
}
]
},
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160518",
"values": "1"
}
]
},
{
"name": "Noely Rios",
"role": "developer",
"values": [
{
"key": "20160505",
"values": "8"
},
{
"key": "20160506",
"values": "6"
},
{
"key": "20160509",
"values": "8"
},
{
"key": "20160510",
"values": "7"
},
{
"key": "20160511",
"values": "8"
},
{
"key": "20160512",
"values": "8"
},
{
"key": "20160513",
"values": "8"
},
{
"key": "20160517",
"values": "7"
},
{
"key": "20160518",
"values": "6"
},
{
"key": "20160519",
"values": "7"
},
{
"key": "20160520",
"values": "8"
},
{
"key": "20160523",
"values": "8"
},
{
"key": "20160524",
"values": "8"
},
{
"key": "20160525",
"values": "8"
},
{
"key": "20160526",
"values": "8"
},
{
"key": "20160527",
"values": "8"
},
{
"key": "20160530",
"values": "8"
},
{
"key": "20160531",
"values": "7"
}
]
},
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160517",
"values": "2"
}
]
},
{
"name": "Ferran Muntada",
"role": "junior",
"values": [
{
"key": "20160523",
"values": "4"
},
{
"key": "20160524",
"values": "4"
},
{
"key": "20160525",
"values": "8"
},
{
"key": "20160526",
"values": "4"
}
]
},
{
"name": "Oscar Rodriguez",
"role": "junior",
"values": [
{
"key": "20160512",
"values": "5"
},
{
"key": "20160513",
"values": "5"
},
{
"key": "20160530",
"values": "5"
},
{
"key": "20160531",
"values": "5"
}
]
}
]
},
{
"name": "TFS359",
"description": "Gestión de menus basico edición",
"authors": [
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160504",
"values": "4"
},
{
"key": "20160505",
"values": "8"
}
]
}
]
},
{
"name": "Reuniones",
"description": "Reuniones seguimiento y toma de requerimientos",
"authors": [
{
"name": "Albert Lopez",
"role": "senior",
"values": [
{
"key": "20160504",
"values": "2"
}
]
},
{
"name": "Alexis Segarra",
"role": "manager",
"values": [
{
"key": "20160503",
"values": "8"
}
]
},
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160504",
"values": "2"
},
{
"key": "20160519",
"values": "1"
},
{
"key": "20160601",
"values": "3.5"
},
{
"key": "20160609",
"values": "1"
},
{
"key": "20160616",
"values": "2"
}
]
},
{
"name": "Noely Rios",
"role": "developer",
"values": [
{
"key": "20160504",
"values": "2"
},
{
"key": "20160519",
"values": "1"
}
]
},
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160502",
"values": "3"
},
{
"key": "20160503",
"values": "8"
},
{
"key": "20160504",
"values": "3"
},
{
"key": "20160505",
"values": "1"
},
{
"key": "20160506",
"values": "1.5"
},
{
"key": "20160518",
"values": "6"
},
{
"key": "20160519",
"values": "2"
},
{
"key": "20160520",
"values": "1"
},
{
"key": "20160524",
"values": "3"
},
{
"key": "20160525",
"values": "8"
},
{
"key": "20160530",
"values": "3.5"
},
{
"key": "20160531",
"values": "8"
},
{
"key": "20160601",
"values": "4"
},
{
"key": "20160606",
"values": "8"
},
{
"key": "20160607",
"values": "8"
},
{
"key": "20160608",
"values": "1"
},
{
"key": "20160609",
"values": "1"
},
{
"key": "20160610",
"values": "3"
},
{
"key": "20160613",
"values": "2"
},
{
"key": "20160614",
"values": "2"
},
{
"key": "20160615",
"values": "8"
}
]
},
{
"name": "Ferran Muntada",
"role": "junior",
"values": [
{
"key": "20160504",
"values": "2"
},
{
"key": "20160519",
"values": "2"
},
{
"key": "20160616",
"values": "3"
}
]
},
{
"name": "Oscar Rodriguez",
"role": "junior",
"values": [
{
"key": "20160519",
"values": "1"
},
{
"key": "20160601",
"values": "1"
},
{
"key": "20160609",
"values": "1"
},
{
"key": "20160616",
"values": "3"
}
]
},
{
"name": "Santiago Espinosa",
"role": "developer",
"values": [
{
"key": "20160502",
"values": "0.5"
},
{
"key": "20160519",
"values": "1"
}
]
}
]
},
{
"name": "Bugs",
"description": "Bugs fixing",
"authors": [
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160503",
"values": "8"
},
{
"key": "20160504",
"values": "2"
},
{
"key": "20160509",
"values": "4"
},
{
"key": "20160517",
"values": "2"
},
{
"key": "20160518",
"values": "2"
},
{
"key": "20160519",
"values": "2"
},
{
"key": "20160531",
"values": "8"
}
]
},
{
"name": "Noely Rios",
"role": "developer",
"values": [
{
"key": "20160518",
"values": "2"
}
]
},
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160520",
"values": "2"
}
]
},
{
"name": "Oscar Rodriguez",
"role": "junior",
"values": [
{
"key": "20160504",
"values": "1"
},
{
"key": "20160505",
"values": "1"
},
{
"key": "20160506",
"values": "1"
},
{
"key": "20160517",
"values": "5"
},
{
"key": "20160518",
"values": "5"
},
{
"key": "20160519",
"values": "4"
},
{
"key": "20160520",
"values": "5"
},
{
"key": "20160523",
"values": "5"
},
{
"key": "20160525",
"values": "5"
}
]
},
{
"name": "Santiago Espinosa",
"role": "developer",
"values": [
{
"key": "20160502",
"values": "4.5"
},
{
"key": "20160518",
"values": "1"
},
{
"key": "20160530",
"values": "5"
}
]
}
]
},
{
"name": "TFS407",
"description": "Pantalla perfil usuario",
"authors": [
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160502",
"values": "8"
},
{
"key": "20160503",
"values": "7"
},
{
"key": "20160504",
"values": "6"
}
]
}
]
},
{
"name": "TFS404",
"description": "Pantalla admin akamai",
"authors": [
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160517",
"values": "2"
}
]
},
{
"name": "Ferran Mundata",
"role": "junior",
"values": [
{
"key": "20160502",
"values": "4"
},
{
"key": "20160503",
"values": "4"
},
{
"key": "20160504",
"values": "6"
},
{
"key": "20160505",
"values": "4"
}
]
},
{
"name": "Oscar Rodriguez",
"role": "junior",
"values": [
{
"key": "20160502",
"values": "5"
},
{
"key": "20160503",
"values": "5"
},
{
"key": "20160526",
"values": "5"
},
{
"key": "20160527",
"values": "5"
}
]
},
{
"name": "Santiago Espinosa",
"role": "developer",
"values": [
{
"key": "20160512",
"values": "5"
}
]
}
]
}
]
}
}
]
[
{
"project": {
"name": "Cs",
"manager": {
"name": "JM Royo",
"role": "manager",
"ID": "13"
},
"tasks": [
{
"name": "TFS224",
"description": "Diseñar pantalla de composiciones",
"authors": [
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160510",
"values": "8"
},
{
"key": "20160511",
"values": "4"
},
{
"key": "20160512",
"values": "7.5"
},
{
"key": "20160513",
"values": "4"
}
]
}
]
},
{
"name": "TFS341",
"description": "Gestión de menus basico listado",
"authors": [
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160502",
"values": "8"
}
]
},
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160517",
"values": "2"
}
]
}
]
},
{
"name": "TFS358",
"description": "Gestión de menus basico creación",
"authors": [
{
"name": "Albert Lopez",
"role": "senior",
"values": [
{
"key": "20160502",
"values": "8"
},
{
"key": "20160503",
"values": "8"
},
{
"key": "20160504",
"values": "6"
},
{
"key": "20160505",
"values": "8"
},
{
"key": "20160506",
"values": "8"
}
]
},
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160518",
"values": "1"
}
]
},
{
"name": "Noely Rios",
"role": "developer",
"values": [
{
"key": "20160505",
"values": "8"
},
{
"key": "20160506",
"values": "6"
},
{
"key": "20160509",
"values": "8"
},
{
"key": "20160510",
"values": "7"
},
{
"key": "20160511",
"values": "8"
},
{
"key": "20160512",
"values": "8"
},
{
"key": "20160513",
"values": "8"
},
{
"key": "20160517",
"values": "7"
},
{
"key": "20160518",
"values": "6"
},
{
"key": "20160519",
"values": "7"
},
{
"key": "20160520",
"values": "8"
},
{
"key": "20160523",
"values": "8"
},
{
"key": "20160524",
"values": "8"
},
{
"key": "20160525",
"values": "8"
},
{
"key": "20160526",
"values": "8"
},
{
"key": "20160527",
"values": "8"
},
{
"key": "20160530",
"values": "8"
},
{
"key": "20160531",
"values": "7"
}
]
},
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160517",
"values": "2"
}
]
},
{
"name": "Ferran Muntada",
"role": "junior",
"values": [
{
"key": "20160523",
"values": "4"
},
{
"key": "20160524",
"values": "4"
},
{
"key": "20160525",
"values": "8"
},
{
"key": "20160526",
"values": "4"
}
]
},
{
"name": "Oscar Rodriguez",
"role": "junior",
"values": [
{
"key": "20160512",
"values": "5"
},
{
"key": "20160513",
"values": "5"
},
{
"key": "20160530",
"values": "5"
},
{
"key": "20160531",
"values": "5"
}
]
}
]
},
{
"name": "TFS359",
"description": "Gestión de menus basico edición",
"authors": [
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160504",
"values": "4"
},
{
"key": "20160505",
"values": "8"
}
]
}
]
},
{
"name": "Reuniones",
"description": "Reuniones seguimiento y toma de requerimientos",
"authors": [
{
"name": "Albert Lopez",
"role": "senior",
"values": [
{
"key": "20160504",
"values": "2"
}
]
},
{
"name": "Alexis Segarra",
"role": "manager",
"values": [
{
"key": "20160503",
"values": "8"
}
]
},
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160504",
"values": "2"
},
{
"key": "20160519",
"values": "1"
},
{
"key": "20160601",
"values": "3.5"
},
{
"key": "20160609",
"values": "1"
},
{
"key": "20160616",
"values": "2"
}
]
},
{
"name": "Noely Rios",
"role": "developer",
"values": [
{
"key": "20160504",
"values": "2"
},
{
"key": "20160519",
"values": "1"
}
]
},
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160502",
"values": "3"
},
{
"key": "20160503",
"values": "8"
},
{
"key": "20160504",
"values": "3"
},
{
"key": "20160505",
"values": "1"
},
{
"key": "20160506",
"values": "1.5"
},
{
"key": "20160518",
"values": "6"
},
{
"key": "20160519",
"values": "2"
},
{
"key": "20160520",
"values": "1"
},
{
"key": "20160524",
"values": "3"
},
{
"key": "20160525",
"values": "8"
},
{
"key": "20160530",
"values": "3.5"
},
{
"key": "20160531",
"values": "8"
},
{
"key": "20160601",
"values": "4"
},
{
"key": "20160606",
"values": "8"
},
{
"key": "20160607",
"values": "8"
},
{
"key": "20160608",
"values": "1"
},
{
"key": "20160609",
"values": "1"
},
{
"key": "20160610",
"values": "3"
},
{
"key": "20160613",
"values": "2"
},
{
"key": "20160614",
"values": "2"
},
{
"key": "20160615",
"values": "8"
}
]
},
{
"name": "Ferran Muntada",
"role": "junior",
"values": [
{
"key": "20160504",
"values": "2"
},
{
"key": "20160519",
"values": "2"
},
{
"key": "20160616",
"values": "3"
}
]
},
{
"name": "Oscar Rodriguez",
"role": "junior",
"values": [
{
"key": "20160519",
"values": "1"
},
{
"key": "20160601",
"values": "1"
},
{
"key": "20160609",
"values": "1"
},
{
"key": "20160616",
"values": "3"
}
]
},
{
"name": "Santiago Espinosa",
"role": "developer",
"values": [
{
"key": "20160502",
"values": "0.5"
},
{
"key": "20160519",
"values": "1"
}
]
}
]
},
{
"name": "Bugs",
"description": "Bugs fixing",
"authors": [
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160503",
"values": "8"
},
{
"key": "20160504",
"values": "2"
},
{
"key": "20160509",
"values": "4"
},
{
"key": "20160517",
"values": "2"
},
{
"key": "20160518",
"values": "2"
},
{
"key": "20160519",
"values": "2"
},
{
"key": "20160531",
"values": "8"
}
]
},
{
"name": "Noely Rios",
"role": "developer",
"values": [
{
"key": "20160518",
"values": "2"
}
]
},
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160520",
"values": "2"
}
]
},
{
"name": "Oscar Rodriguez",
"role": "junior",
"values": [
{
"key": "20160504",
"values": "1"
},
{
"key": "20160505",
"values": "1"
},
{
"key": "20160506",
"values": "1"
},
{
"key": "20160517",
"values": "5"
},
{
"key": "20160518",
"values": "5"
},
{
"key": "20160519",
"values": "4"
},
{
"key": "20160520",
"values": "5"
},
{
"key": "20160523",
"values": "5"
},
{
"key": "20160525",
"values": "5"
}
]
},
{
"name": "Santiago Espinosa",
"role": "developer",
"values": [
{
"key": "20160502",
"values": "4.5"
},
{
"key": "20160518",
"values": "1"
},
{
"key": "20160530",
"values": "5"
}
]
}
]
},
{
"name": "TFS407",
"description": "Pantalla perfil usuario",
"authors": [
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160502",
"values": "8"
},
{
"key": "20160503",
"values": "7"
},
{
"key": "20160504",
"values": "6"
}
]
}
]
},
{
"name": "TFS404",
"description": "Pantalla admin akamai",
"authors": [
{
"name": "JM Royo",
"role": "manager",
"values": [
{
"key": "20160517",
"values": "2"
}
]
},
{
"name": "Ferran Mundata",
"role": "junior",
"values": [
{
"key": "20160502",
"values": "4"
},
{
"key": "20160503",
"values": "4"
},
{
"key": "20160504",
"values": "6"
},
{
"key": "20160505",
"values": "4"
}
]
},
{
"name": "Oscar Rodriguez",
"role": "junior",
"values": [
{
"key": "20160502",
"values": "5"
},
{
"key": "20160503",
"values": "5"
},
{
"key": "20160526",
"values": "5"
},
{
"key": "20160527",
"values": "5"
}
]
},
{
"name": "Santiago Espinosa",
"role": "developer",
"values": [
{
"key": "20160512",
"values": "5"
}
]
}
]
}
]
}
},
{
"project": {
"name": "Codu",
"manager": {
"name": "JM Royo",
"role": "manager",
"ID": "A0001"
},
"tasks": [
{
"name": "PDF",
"authors": [
{
"name": "David Balasch",
"role": "developer",
"values": [
{
"key": "20160601",
"values": "5"
},
{
"key": "20160602",
"values": "8"
},
{
"key": "20160608",
"values": "7"
}
]
},
{
"name": "Santiago Espinosa",
"role": "developer",
"values": [
{
"key": "20160602",
"values": "7"
},
{
"key": "20160603",
"values": "7"
},
{
"key": "20160610",
"values": "7"
}
]
},
{
"name": "Gerard Bruno",
"role": "developer",
"values": [
{
"key": "20160606",
"values": "7"
},
{
"key": "20160608",
"values": "7"
},
{
"key": "20160609",
"values": "7"
},
{
"key": "20160610",
"values": "7"
},
{
"key": "20160627",
"values": "7"
},
{
"key": "20160628",
"values": "7"
},
{
"key": "20160629",
"values": "7"
},
{
"key": "20160630",
"values": "7"
},
{
"key": "20160701",
"values": "7"
},
{
"key": "20160804",
"values": "7"
}
]
}
]
},
{
"name": "Links",
"authors": [
{
"name": "Albert López",
"role": "senior",
"values": [
{
"key": "20160616",
"values": "5"
},
{
"key": "20160617",
"values": "8"
}
]
},
{
"name": "Marta Barcia",
"role": "junior",
"values": [
{
"key": "20160615",
"values": "5"
},
{
"key": "20160616",
"values": "5"
},
{
"key": "20160617",
"values": "5"
},
{
"key": "20160620",
"values": "6"
},
{
"key": "20160621",
"values": "4"
}
]
}
]
},
{
"name": "Bugs",
"authors": [
{
"name": "Albert López",
"role": "senior",
"values": [
{
"key": "20160609",
"values": "1"
},
{
"key": "20160610",
"values": "5"
},
{
"key": "20160613",
"values": "2"
}
]
},
{
"name": "Oscar Muntal",
"role": "developer",
"values": [
{
"key": "20160613",
"values": "5"
},
{
"key": "20160614",
"values": "5"
},
{
"key": "20160615",
"values": "6"
},
{
"key": "20160616",
"values": "4"
}
]
},
{
"name": "Santiago Espinosa",
"role": "developer",
"values": [
{
"key": "20160613",
"values": "5"
},
{
"key": "20160614",
"values": "4"
},
{
"key": "20160615",
"values": "3"
},
{
"key": "20160616",
"values": "1"
},
{
"key": "20160617",
"values": "1"
}
]
}
]
},
{
"name": "Deploy",
"authors": [
{
"name": "Albert López",
"role": "senior",
"values": [
{
"key": "20160620",
"values": "5"
},
{
"key": "20160621",
"values": "2"
},
{
"key": "20160623",
"values": "1"
}
]
},
{
"name": "Oscar Muntal",
"role": "developer",
"values": [
{
"key": "20160620",
"values": "1"
}
]
},
{
"name": "Santiago Espinosa",
"role": "developer",
"values": [
{
"key": "20160620",
"values": "5"
},
{
"key": "20160621",
"values": "4"
}
]
}
]
}
]
}
}
]
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.16/d3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chroma-js/1.4.0/chroma.min.js"></script>
<link rel="stylesheet" href="style.css">
<button id="toggle" class="bt">Expand/Collapse</button>
<button id="numbers" class="bt">Numbers/Color</button>
<div id="table"></div>
<script>
var margin = {top: 90, right: 10, bottom: 20, left: 25 },
width = parseInt(d3.select('#table').style('width'), 10),
width = width - margin.left - margin.right,
height = 1200 - margin.top - margin.bottom;
var cellSeparation = 1,
cellSize = 20,
percent = d3.format(".1%");
var line_h = 160;
var formatTime = function(input, formatInput, formatOutput){
var dateParse = d3.time.format(formatInput).parse;
var dateFormat = d3.time.format(formatOutput);
return dateFormat(dateParse(input));
};
var author_cost = {
manager: 20,
senior: 15,
developer: 10,
junior: 6,
}
var calculeCost = function(hours, position){
return hours * author_cost[position];
}
var colorScale = chroma.scale('YlGn').domain([-1,10]).mode('lch');
var ctScale = chroma.scale('PuBu').domain([0, 500]).mode('lch');
var roleScale = d3.scale.category10();
d3.json('data-one.json', function(e, data){
var total_roles = [];
// Calcule totals
data.forEach(function(d) {
var total_task = [];
var total_author = [];
// Order project's tasks by name
d.project.tasks.sort(function(a, b){
return d3.ascending(a.name, b.name);
});
d.project.tasks.forEach(function(j, k) {
// Order team members by role
j.authors.sort(function(a, b){
return d3.ascending(a.role, b.role);
});
// Calcule how much cost a team member each day
j.authors.forEach(function(w) {
if(total_roles.indexOf(w.role) == -1) total_roles.push(w.role);
w.values.forEach(function(s) {
s.expenses = calculeCost(s.values, w.role);
total_task.push(s);
});
total_author.push(w);
});
});
// Recolect data to get all day's expenses
var task_nested = d3.nest()
.key(function(j) { return j.key; })
.rollup(function(s) {
var t = 0;
s.forEach(function(x){
t += +x.expenses;
})
return t;
})
.entries(total_task);
task_nested.forEach(function(j, k, a){
if (k > 0) a[k].sumatory = a[k].values + a[k-1].sumatory;
else a[k].sumatory = a[k].values;
});
d.project.total_expense = task_nested;
// Generate a new task with the total time each team member has
// put in all the tasks
var author_nested = d3.nest()
.key(function(j) { return j.name; })
.entries(total_author);
author_nested.forEach(function(j){
var alltasks = [];
j.values.forEach(function(s,t,u){
s.values.forEach(function(x){
alltasks = alltasks.concat(x)
});
});
j.values = d3.nest()
.key(function(s){ return s.key})
.rollup(function(s){
var t = 0;
s.forEach(function(x){
t += +x.values;
})
return t;
})
.entries(alltasks);
j.name = j.key;
delete j.key;
});
var newtask = {};
newtask.name = "Totals";
newtask.authors = author_nested;
d.project.tasks.splice(0, 0, newtask);
// Calcule the total time for each team member for all the time
d.project.tasks[0].authors.forEach(function(j) {
var total_period = 0;
j.values.forEach(function(w) {
total_period += w.values;
});
j.total_period = total_period;
});
});
// Calcule first day
var min_date = d3.min(data, function(d){
return d3.min(d.project.tasks, function(e){
return d3.min(e.authors, function(f){
return d3.min(f.values, function(g){ return g.key; });
});
});
});
// Calcule last day
var max_date = d3.max(data, function(d){
return d3.max(d.project.tasks, function(e){
return d3.max(e.authors, function(f){
return d3.max(f.values, function(g){ return g.key; });
});
});
});
var diff_date = (new Date(formatTime(max_date, '%Y%m%d', '%Y,%m,%d')) - new Date(formatTime(min_date, '%Y%m%d', '%Y,%m,%d')))/1000/60/60/24;
var xScale = d3.time.scale()
.domain([new Date(formatTime(min_date, '%Y%m%d', '%Y,%m,%d')), new Date(formatTime(max_date, '%Y%m%d', '%Y,%m,%d'))])
.range([167.5, ((cellSize+cellSeparation)*diff_date)+167.5])
.nice();
// Axis (day)
var xAxis = d3.svg.axis()
.orient("top")
.ticks(d3.time.day)
.tickFormat(d3.time.format("%_d"))
.scale(xScale);
// Axis (month)
var xAxisBig = d3.svg.axis()
.orient("top")
.ticks(d3.time.month)
.tickFormat(d3.time.format("%_B %Y"))
.scale(xScale);
// SVG CANVAS
var svg = d3.select('#table')
.append('svg')
.attr('id', 'chart')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.attr("class", "artwork collapsed");
// GENERAL GROUP
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// X AXIS GROUP
var xGroup = g.append("g")
.attr("class", "axis axis--x");
xGroup.append("g")
.attr("class", "axis--month")
.attr("transform", "translate("+(cellSize*0.5)+",-25)")
.call(xAxisBig)
.selectAll('line')
.attr("transform", "rotate(-90)")
.attr('y1', -cellSize*0.5)
.attr('y2', function(d){
var di = new Date(d);
var df = new Date(d);
df.setMonth(d.getMonth()+1)
var dl = new Date(new Date(df) - new Date(di))/(1000*60*60*24)
return (dl*cellSize)-45;
});
xGroup.selectAll(".axis--month text")
.style("text-anchor", "start")
xGroup.append("g")
.attr("class", "axis--day")
.attr("transform", "translate("+(cellSize*0.5)+",0)")
.call(xAxis);
// PROJECTS GROUPS
var projects = g.selectAll('.project')
.data(data)
.enter()
.append('g')
.attr('class', 'project')
.attr("transform", function(d,i){
return "translate( 0," + (cellSize+cellSeparation)*i + ")"
});
// Lines between projects
var project_lines = projects.append('line')
.attr('x1', 0)
.attr('y1', 0)
.attr('x2', xScale(new Date(formatTime(max_date, '%Y%m%d', '%Y,%m,%d')))+cellSize)
.attr('y2', 0)
.attr('class', 'separator');
// Project's name
projects.append('text')
.attr("y", cellSize+cellSeparation-6)
.attr("x", 0)
.attr("class", "project--name")
.style('font-weight', 'bolder')
.style('text-transform', 'uppercase')
.text(function(d){
return d.project.name;
});
// TASKS GROUP
var tasks = projects.selectAll('.tasks')
.data( function(d){ return d.project.tasks;})
.enter()
.append('g')
.attr('class', 'tasks')
.style('opacity', '0');
// Lines between tasks
var task_lines = tasks.append('line')
.attr('x1', 0)
.attr('y1', 0)
.attr('x2', xScale(new Date(formatTime(max_date, '%Y%m%d', '%Y,%m,%d')))+cellSize)
.attr('y2', 0)
.attr('class', 'separator')
.style('opacity', 0.2);
// Task's name
var task_name = tasks.append('text')
.attr("y", cellSize+cellSeparation-5)
.attr("x", 0)
.attr("class", "task--name")
.style('font-weight', 'bolder')
.text(function(d){
return d.name;
});
task_name.append('title')
.text(function(d){
return d.description;
})
// AUTHORS GROUP
var authors = tasks.selectAll('.authors')
.data(function(d){ return d.authors;})
.enter()
.append('g')
.attr('class', 'authors');
// Author's name
var authors_name = authors.append('text')
.attr("y", cellSize+cellSeparation-5)
.attr("x", 0)
.attr("class", "author--name")
.style('opacity', '0')
.text(function(d){
return d.name;
});
authors_name.on('click', function(d) {
if(!d3.select(this).classed('active')){
authors.style('opacity', '1')
.filter(function(j) {
return j.name != d.name
})
.style('opacity', '0.1');
authors_name.filter(function(j) {
return j.name == d.name
}).classed('active', true);
}else{
authors.style('opacity', '1');
authors_name.classed('active', false);
}
});
// Author's name tooltip
authors_name.append('title')
.text(function(d){
return d.name +': '+ d.role;
});
// Author's role category
var authors_role = authors.append('circle')
.attr('r', 6)
.attr('cx', -8)
.attr('cy', (cellSize/2)+2)
.attr('class', 'author--role')
.style('fill', function(d, i){
return roleScale(d.role);
});
authors_role.on('click', function(d) {
if(!d3.select(this).classed('active')){
authors.style('opacity', '1')
.filter(function(j) {
return j.role != d.role
})
.style('opacity', '0.1');
authors_role.filter(function(j) {
return j.role == d.role
})
.classed('active', true);
}else{
authors.style('opacity', '1');
authors_role.classed('active', false);
}
});
// values (number)
authors.append('g').selectAll('text')
.data(function(d){ return d.values;})
.enter()
.append('text')
.attr('class', 'datetime datetime__author')
.attr('y', (cellSize-6))
.attr('x', function(d,i){
return xScale(new Date(formatTime(d.key, '%Y%m%d', '%Y,%m,%d')))-1+cellSize*0.5;
})
.attr('text-anchor', 'middle')
.text(function(d,i){
return d.values;
});
// values (rect)
var loads = authors.append('g').selectAll('rect')
.data(function(d){ return d.values;})
.enter()
.append('rect')
.attr('width', cellSize)
.attr('height', cellSize)
.attr('y', '0')
.attr('x', function(d,i){
return xScale(new Date(formatTime(d.key, '%Y%m%d', '%Y,%m,%d')));
})
.style("fill", function(d){
if (d.values<=8) return colorScale(d.values);
else return '#dd1c77';
});
// TOTAL EXPENSES GROUP
var total_expense = projects.append('g')
.attr('class', 'total_expense');
// Total values
total_expense.selectAll('text')
.data(function(d){ return d.project.total_expense; })
.enter()
.append('text')
.attr('class', 'datetime datetime__total')
.attr('y', (cellSize+cellSeparation-7))
.attr('x', function(d,i){
return xScale(new Date(formatTime(d.key, '%Y%m%d', '%Y,%m,%d')))+cellSize*0.5;
})
.attr('text-anchor', 'middle')
.text(function(d,i){
return d.values;
});
// Total rects
total_expense.selectAll('rect')
.data(function(d){ return d.project.total_expense; })
.enter()
.append('rect')
.attr('width', cellSize)
.attr('height', cellSize)
.attr('y', '0')
.attr('x', function(d,i){
return xScale(new Date(formatTime(d.key, '%Y%m%d', '%Y,%m,%d')));
})
.style("fill", function(d){
return ctScale(d.values);
})
.append('title').text(function(d,i){
return d.values+"€";
});
// LEYENDS GROUP
var leyendGroup = g.append('g')
.attr('class', 'leyend')
.attr('transform', 'translate('+167.5+',' + (-65) + ')');
leyend = leyendGroup.selectAll('g')
.data(total_roles)
.enter().append('g')
.attr('class', 'role')
.attr('transform', function(d, i) { return 'translate('+i*100+',0)'; })
leyend.append('text')
.attr('transform', 'translate(10,0)')
.text(function(d) { return d; });
leyend.append('circle')
.attr('r', 6)
.attr('cx', 0)
.attr('cy', -4)
.style('fill', function(d) { return roleScale(d); })
leyend.on('click', function(d) {
if(!d3.select(this).classed('active')){
authors.style('opacity', '1')
.filter(function(j) {
return j.role != d;
})
.style('opacity', '0.1');
authors_role.filter(function(j) {
return j.role == d;
})
.classed('active', true);
d3.select(this).classed('active', true);
}else{
authors.style('opacity', '1');
authors_role.classed('active', false);
d3.select(this).classed('active', false);
}
});
// TOTAL PERIOD GROUP
var total_time = projects.append('g')
.attr('class', 'total-time');
//console.log(total_time.data());
var total_time_load = total_time.selectAll('.totalbyauth')
.data(function(d) {
return d.project.tasks[0].authors;
})
.enter().append('g')
.attr('class', 'totalbyauth')
.append('rect')
.attr('x', xScale(new Date(formatTime(max_date, '%Y%m%d', '%Y,%m,%d')))+cellSize*2)
.attr('y', function(d, i) { console.log(d); return cellSize*(i+2); })
.attr('width', cellSize)
.attr('height', cellSize)
.style('fill', function(d) {
return ;
});
total_time_load.append('title')
.text(function(d) { return d.name; })
// EVENTS BINDING
d3.select('#toggle').on("click", function(){
if(d3.select('#chart').classed('collapsed')) expand_values();
else collapse();
d3.select(this).attr('class', function(){
return d3.select(this).classed('active') ? null : 'active';
});
});
d3.select('#numbers').on("click", function(){
d3.select(this).attr('class', function(){
return d3.select(this).classed('active') ? null : 'active';
});
d3.select('#chart').classed('numbers', function(){
return d3.select('#numbers').classed('active') ? true : false;
});
});
function collapse() {
d3.select('#chart').attr('class', 'artwork collapsed');
authors.transition()
.attr("transform", "translate(0,0)");
authors_name.transition().style('opacity', '0');
tasks.transition()
.attr("transform", "translate(0,0)")
.style('opacity', '0');
projects.transition()
.attr("transform", function(d,i){
return "translate( 0," + (cellSize+cellSeparation)*i + ")"
});
project_lines.transition()
.attr('x2', xScale(new Date(formatTime(max_date, '%Y%m%d', '%Y,%m,%d')))+cellSize);
total_expense.transition()
.attr("transform", "translate(0,0)");
xGroup.transition()
.attr("transform", "translate(0,0)");
}
function expand_values() {
d3.select('#chart').attr('class', 'artwork expanded', false);
authors.transition()
.delay(function(d,i){
return (i*200)+600;
})
.attr("transform", function(d,i){
return "translate( 0," + cellSize*(i+1) + ")"
});
authors_name.transition()
.style('opacity', '1')
.delay(function(d,i){
return (i*200)+200;
});
tasks.transition()
.delay(function(d,i){
return (i*200)+400;
})
.style('opacity', '1')
.attr("transform", function(d,i,a){
var prev_load_length = 0;
if(i>0) {
for (var j = 0; j < i; j++){
prev_load_length += data[a].project.tasks[j].authors.length;
}
}
return "translate(0," + cellSize*(prev_load_length+(i+1)) + ")";
});
projects.transition()
.delay(200)
.attr("transform", function(d,i){
var prev_load_length = 0;
if (i > 0){
projects.data()[i-1].project.tasks.forEach(function(j,k){
prev_load_length += projects.data()[i-1].project.tasks[k].authors.length +1;
});
}
return "translate( 0," + cellSize*((prev_load_length)+(i*2)) + ")"
});
}
});
</script>
</body>
@import 'https://fonts.googleapis.com/css?family=Open+Sans';
* { font-family: 'Open Sans', sans-serif; font-size: 12px;}
#table {
width: 1200px;
}
#chart .task--name,
#chart .author--name {
transition: opacity 200ms ease-out;
transition-delay: 200ms;
}
#chart .author--name,
#chart .authors circle {
cursor: pointer;
}
#chart .author--name:hover {
fill: #CCC;
}
#chart .total_expense rect:hover,
#chart .authors rect:hover {
opacity: 0.2 !important;
}
#chart .author--role:hover {
opacity: 0.5;
transition-delay: 0;
}
#chart .authors,
#chart .totals,
#chart .separator {
transition: opacity 0.5s ease-out;
}
#chart.collapsed .task--name,
#chart.collapsed .author--name,
#chart.collapsed .author--role,
#chart.collapsed .authors rect,
#chart.collapsed .authors .datetime,
#chart.collapsed .separator {
opacity: 0;
}
#chart.collapsed .task--name,
#chart.collapsed .author--role,
#chart.collapsed .author--name {
transition: opacity 200ms ease-out;
transition-delay: 0ms;
}
#chart.collapsed .totals {
opacity: 1;
}
/* Datetime numbers */
#chart .datetime {
transition: opacity 200ms ease-in;
font-size: 10px;
pointer-events: none;
}
#chart.numbers .datetime {
opacity: 1;
}
#chart.numbers rect {
opacity: 0.2;
}
/* Axis */
#chart .leyend {
opacity: 0;
transition: opacity 350ms ease;
transition-delay: 500ms;
}
#chart.collapsed .leyend {
pointer-events:none;
}
#chart.expanded .leyend {
opacity: 1;
}
#chart .leyend .role {
cursor: pointer;
}
#chart .leyend .role:hover {
opacity: 0.5;
}
#chart .axis text {
font-size: 10px;
}
#chart .axis path {
display: none;
}
#chart line,
#chart .separator{
fill: none;
stroke: black;
stroke-width: 1px;
shape-rendering: crispEdges;
opacity: 0.5;
}
#chart .axis--day text {
text-anchor: middle;
}
#chart .axis--day line {
display: none;
}
#chart .axis--month text {
text-anchor: start;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment