Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clickable gantt tasks #804

Merged
merged 22 commits into from
Jun 9, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
e298351
Added <a href> and callback functionality to gantt diagrams
abzicht Mar 7, 2019
19d9dd6
Fixed clickStatement to include ids
abzicht Mar 7, 2019
57b780a
In render: added calling callback for gantt functions
abzicht Mar 7, 2019
67ee649
Added setLink and setClickEvent to gantt
abzicht Mar 7, 2019
0c66e1b
Added href support and improved callback argument handling
abzicht Mar 9, 2019
1005721
Fixed issue which only passed the first char of functionargs to the f…
abzicht Mar 9, 2019
4587f5a
Added 'clickable' class to all elements with interactivity. This allo…
abzicht Mar 9, 2019
856591d
Removed STR as it is no longer required; made 'click' a state such th…
abzicht Mar 9, 2019
d169641
Fixed lint issue
abzicht Mar 9, 2019
20b35cb
Removed STR remains and fixed whitespace issue for 'call' which lead …
abzicht Mar 9, 2019
b322a96
Code refactoring: Pushing functions is now to the funs list is now av…
abzicht Mar 9, 2019
6fd7905
Removed <a> tag, moved id attribute to text section
abzicht Mar 9, 2019
91651ca
Fixed lint issues
abzicht Mar 9, 2019
6c84544
Changed href to scan for the next double quoted word. This allows whi…
abzicht Mar 10, 2019
1dfff7a
Added documentation and implemented empty functionarguments
abzicht Mar 10, 2019
63184d5
Argument processing now allows double quoted strings
abzicht Mar 10, 2019
fa04e3d
Adding jison processed js file because it seems that this is always c…
abzicht Mar 10, 2019
d2eb507
Adding styles for clickable tasks
abzicht Mar 10, 2019
c44ff8a
Adding a gantt clickable example to the existing gantt diagram
abzicht Mar 10, 2019
6ede0f6
Allowing brackets in taskTxt, adjusted index.html example to include …
abzicht Mar 10, 2019
f272cff
Adding minify capability
abzicht Mar 10, 2019
0a7b884
Added css for clickable when task text is outside of task
abzicht Mar 15, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions dist/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,13 @@
Add gantt diagram to demo page :after a1 , 20h
Add another diagram to demo page :doc1, after a1 , 48h

section Clickable
Visit mermaidjs :active, cl1, 2014-01-07,2014-01-10
Calling a Callback (look at the console log) :cl2, after cl1, 3d

click cl1 href "https://mermaidjs.github.io/"
click cl2 call ganttTestClick("test", test, test)

section Last section
Describe gantt syntax :after doc1, 3d
Add gantt diagram to demo page : 20h
Expand Down Expand Up @@ -346,6 +353,11 @@
});
</script>
<script>
function ganttTestClick(a, b, c){
console.log("a:", a)
console.log("b:", b)
console.log("c:", c)
}
function testClick(nodeId) {
console.log("clicked", nodeId)
var originalBgColor = document.querySelector('body').style.backgroundColor
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"scripts": {
"build": "webpack --progress --colors",
"build:watch": "yarn build --watch",
"minify": "minify ./dist/mermaid.js > ./dist/mermaid.min.js",
"release": "yarn build -p --config webpack.config.prod.babel.js",
"lint": "standard",
"test": "yarn lint && jest",
Expand All @@ -25,7 +26,7 @@
},
"repository": {
"type": "git",
"url": "https://github.com/knsv/mermaid"
"url": "https://github.com/abzicht/mermaid"
},
"author": "Knut Sveidqvist",
"license": "MIT",
Expand All @@ -42,6 +43,7 @@
"graphlibrary": "^2.2.0",
"he": "^1.2.0",
"lodash": "^4.17.11",
"minify": "^4.1.1",
"moment": "^2.23.0",
"scope-css": "^1.2.1"
},
Expand Down Expand Up @@ -84,4 +86,4 @@
"babel-core"
]
}
}
}
151 changes: 140 additions & 11 deletions src/diagrams/gantt/ganttDb.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import moment from 'moment'
import { logger } from '../../logger'
import {
logger
} from '../../logger'
import * as d3 from 'd3'

let dateFormat = ''
let axisFormat = ''
let title = ''
let sections = []
let tasks = []
let currentSection = ''
let funs = []

export const clear = function () {
sections = []
tasks = []
currentSection = ''
funs = []
title = ''
taskCnt = 0
lastTask = undefined
Expand Down Expand Up @@ -242,18 +247,33 @@ const parseData = function (prevTaskId, dataStr) {
switch (data.length) {
case 1:
task.id = parseId()
task.startTime = { type: 'prevTaskEnd', id: prevTaskId }
task.endTime = { data: data[0] }
task.startTime = {
type: 'prevTaskEnd',
id: prevTaskId
}
task.endTime = {
data: data[0]
}
break
case 2:
task.id = parseId()
task.startTime = { type: 'getStartDate', startData: data[0] }
task.endTime = { data: data[1] }
task.startTime = {
type: 'getStartDate',
startData: data[0]
}
task.endTime = {
data: data[1]
}
break
case 3:
task.id = parseId(data[0])
task.startTime = { type: 'getStartDate', startData: data[1] }
task.endTime = { data: data[2] }
task.startTime = {
type: 'getStartDate',
startData: data[1]
}
task.endTime = {
data: data[2]
}
break
default:
}
Expand All @@ -270,8 +290,11 @@ export const addTask = function (descr, data) {
section: currentSection,
type: currentSection,
processed: false,
raw: { data: data },
task: descr
raw: {
data: data
},
task: descr,
classes: []
}
const taskInfo = parseData(lastTaskID, data)
rawTask.raw.startTime = taskInfo.startTime
Expand Down Expand Up @@ -299,7 +322,8 @@ export const addTaskOrg = function (descr, data) {
section: currentSection,
type: currentSection,
description: descr,
task: descr
task: descr,
classes: []
}
const taskInfo = compileData(lastTask, data)
newTask.startTime = taskInfo.startTime
Expand Down Expand Up @@ -348,6 +372,108 @@ const compileTasks = function () {
return allProcessed
}

/**
* Called by parser when a link is found. Adds the URL to the vertex data.
* @param ids Comma separated list of ids
* @param linkStr URL to create a link for
*/
export const setLink = function (ids, linkStr) {
ids.split(',').forEach(function (id) {
let rawTask = findTaskById(id)
if (typeof rawTask !== 'undefined') {
pushFun(id, () => { window.open(linkStr, '_self') })
}
})
setClass(ids, 'clickable')
}

/**
* Called by parser when a special node is found, e.g. a clickable element.
* @param ids Comma separated list of ids
* @param className Class to add
*/
export const setClass = function (ids, className) {
ids.split(',').forEach(function (id) {
let rawTask = findTaskById(id)
if (typeof rawTask !== 'undefined') {
rawTask.classes.push(className)
}
})
}

const setClickFun = function (id, functionName, functionArgs) {
if (typeof functionName === 'undefined') {
return
}

let argList = []
if (typeof functionArgs === 'string') {
/* Splits functionArgs by ',', ignoring all ',' in double quoted strings */
argList = functionArgs.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/)
for (let i = 0; i < argList.length; i++) {
let item = argList[i].trim()
/* Removes all double quotes at the start and end of an argument */
/* This preserves all starting and ending whitespace inside */
if (item.charAt(0) === '"' && item.charAt(item.length - 1) === '"') {
item = item.substr(1, item.length - 2)
}
argList[i] = item
}
}

let rawTask = findTaskById(id)
if (typeof rawTask !== 'undefined') {
pushFun(id, () => { window[functionName](...argList) })
}
}

/**
* The callbackFunction is executed in a click event bound to the task with the specified id or the task's assigned text
* @param id The task's id
* @param callbackFunction A function to be executed when clicked on the task or the task's text
*/
const pushFun = function (id, callbackFunction) {
funs.push(function (element) {
const elem = d3.select(element).select(`[id="${id}"]`)
if (elem !== null) {
elem.on('click', function () {
callbackFunction()
})
}
})
funs.push(function (element) {
const elem = d3.select(element).select(`[id="${id}-text"]`)
if (elem !== null) {
elem.on('click', function () {
callbackFunction()
})
}
})
}

/**
* Called by parser when a click definition is found. Registers an event handler.
* @param ids Comma separated list of ids
* @param functionName Function to be called on click
* @param functionArgs Function args the function should be called with
*/
export const setClickEvent = function (ids, functionName, functionArgs) {
ids.split(',').forEach(function (id) {
setClickFun(id, functionName, functionArgs)
})
setClass(ids, 'clickable')
}

/**
* Binds all functions previously added to fun (specified through click) to the element
* @param element
*/
export const bindFunctions = function (element) {
funs.forEach(function (fun) {
fun(element)
})
}

export default {
clear,
setDateFormat,
Expand All @@ -359,5 +485,8 @@ export default {
getTasks,
addTask,
findTaskById,
addTaskOrg
addTaskOrg,
setClickEvent,
setLink,
bindFunctions
}
34 changes: 24 additions & 10 deletions src/diagrams/gantt/ganttRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export const draw = function (text, id) {
.enter()

rectangles.append('rect')
.attr('id', function (d) { return d.id })
.attr('rx', 3)
.attr('ry', 3)
.attr('x', function (d) {
Expand All @@ -141,6 +142,11 @@ export const draw = function (text, id) {
.attr('class', function (d) {
const res = 'task '

let classStr = ''
if (d.classes.length > 0) {
classStr = d.classes.join(' ')
}

let secNum = 0
for (let i = 0; i < categories.length; i++) {
if (d.type === categories[i]) {
Expand All @@ -150,28 +156,30 @@ export const draw = function (text, id) {

if (d.active) {
if (d.crit) {
return res + ' activeCrit' + secNum
return res + classStr + ' activeCrit' + secNum
} else {
return res + ' active' + secNum
return res + classStr + ' active' + secNum
}
}

if (d.done) {
if (d.crit) {
return res + ' doneCrit' + secNum
return res + classStr + ' doneCrit' + secNum
} else {
return res + ' done' + secNum
return res + classStr + ' done' + secNum
}
}

if (d.crit) {
return res + ' crit' + secNum
return res + classStr + ' crit' + secNum
}

return res + ' task' + secNum
return res + classStr + ' task' + secNum
})

rectangles.append('text')
rectangles
.append('text')
.attr('id', function (d) { return d.id + '-text' })
.text(function (d) {
return d.task
})
Expand Down Expand Up @@ -200,6 +208,12 @@ export const draw = function (text, id) {
const startX = timeScale(d.startTime)
const endX = timeScale(d.endTime)
const textWidth = this.getBBox().width

let classStr = ''
if (d.classes.length > 0) {
classStr = d.classes.join(' ')
}

let secNum = 0
for (let i = 0; i < categories.length; i++) {
if (d.type === categories[i]) {
Expand Down Expand Up @@ -231,12 +245,12 @@ export const draw = function (text, id) {
// Check id text width > width of rectangle
if (textWidth > (endX - startX)) {
if (endX + textWidth + 1.5 * conf.leftPadding > w) {
return 'taskTextOutsideLeft taskTextOutside' + secNum + ' ' + taskType
return classStr + ' taskTextOutsideLeft taskTextOutside' + secNum + ' ' + taskType
} else {
return 'taskTextOutsideRight taskTextOutside' + secNum + ' ' + taskType
return classStr + ' taskTextOutsideRight taskTextOutside' + secNum + ' ' + taskType
}
} else {
return 'taskText taskText' + secNum + ' ' + taskType
return classStr + ' taskText taskText' + secNum + ' ' + taskType
}
})
}
Expand Down
Loading