gantt-elastic正常甘特图连接线
优化后甘特图连接线
由于甘特图连接线不带箭头指向样式,所以手动修改node包文件
包的这个文件(node_modules\gantt-elastic\src\components\Chart\DependencyLines.vue)
(懒得标注修改哪了,直接整个文件替换就好)
<!--
/**
* @fileoverview DependencyLines component
* @license MIT
* @author Rafal Pospiech <neuronet.io@gmail.com>
* @package GanttElastic
*/
-->
<template>
<svg
x="0"
y="0"
width="100%"
height="100%"
class="gantt-elastic__chart-dependency-lines-container"
:style="{ ...root.style['chart-dependency-lines-container'] }"
>
<g v-for="task in dependencyTasks" :key="task.id" :task="task">
<defs>
<marker id="markerArrow" markerWidth="8" markerHeight="8" refX="7" refY="5" orient="auto">
<path d="M2,2 L2,8 L8,5 L2,2" style="fill: rgb(255 129 0)" />
</marker>
</defs>
<path
class="gantt-elastic__chart-dependency-lines-path"
style=" marker-end: url(#markerArrow)"
:style="{
...root.style['chart-dependency-lines-path'],
...task.style['chart-dependency-lines-path'],
...task.style['chart-dependency-lines-path-' + dependencyLine.task_id],
}"
v-for="dependencyLine in task.dependencyLines"
:key="dependencyLine.id"
:task="task"
:d="dependencyLine.points"
></path>
</g>
</svg>
</template>
<script>
export default {
name: 'DependencyLines',
inject: ['root'],
props: ['tasks'],
data() {
return {};
},
methods: {
/**
* Get path points
*
* @param {any} fromTaskId
* @param {any} toTaskId
* @returns {string}
*/
getPoints(fromTaskId, toTaskId) {
const fromTask = this.root.getTask(fromTaskId);
const toTask = this.root.getTask(toTaskId);
if (
fromTask === null ||
toTask === null ||
!this.root.isTaskVisible(toTask) ||
!this.root.isTaskVisible(fromTask)
) {
return null;
}
const startX = fromTask.x + fromTask.width;
const startY = fromTask.y + fromTask.height / 2;
const stopX = toTask.x;
const stopY = toTask.y + toTask.height / 2;
const distanceX = stopX - startX;
let distanceY;
let yMultiplier = 1;
if (stopY >= startY) {
distanceY = stopY - startY;
} else {
distanceY = startY - stopY;
yMultiplier = -1;
}
const offset = 10;
const roundness = 4;
const isBefore = distanceX <= offset + roundness;
let points = `M ${startX} ${startY}
L ${startX + offset},${startY} `;
if (isBefore) {
points += `Q ${startX + offset + roundness},${startY} ${startX + offset + roundness},${
startY + roundness * yMultiplier
}
L ${startX + offset + roundness},${startY + (distanceY * yMultiplier) / 2 - roundness * yMultiplier}
Q ${startX + offset + roundness},${startY + (distanceY * yMultiplier) / 2} ${startX + offset},${
startY + (distanceY * yMultiplier) / 2
}
L ${startX - offset + distanceX},${startY + (distanceY * yMultiplier) / 2}
Q ${startX - offset + distanceX - roundness},${startY + (distanceY * yMultiplier) / 2} ${
startX - offset + distanceX - roundness
},${startY + (distanceY * yMultiplier) / 2 + roundness * yMultiplier}
L ${startX - offset + distanceX - roundness},${stopY - roundness * yMultiplier}
Q ${startX - offset + distanceX - roundness},${stopY} ${startX - offset + distanceX},${stopY}
L ${stopX},${stopY}`;
} else {
points += `L ${startX + distanceX / 2 - roundness},${startY}
Q ${startX + distanceX / 2},${startY} ${startX + distanceX / 2},${startY + roundness * yMultiplier}
L ${startX + distanceX / 2},${stopY - roundness * yMultiplier}
Q ${startX + distanceX / 2},${stopY} ${startX + distanceX / 2 + roundness},${stopY}
L ${stopX},${stopY}`;
}
return points;
},
},
computed: {
/**
* Get tasks which are dependent on other tasks
*
* @returns {array}
*/
dependencyTasks() {
return this.tasks
.filter((task) => typeof task.dependentOn !== 'undefined')
.map((task) => {
task.dependencyLines = task.dependentOn.map((id) => {
return { points: this.getPoints(id, task.id), task_id: id };
});
return task;
})
.filter((task) => task.dependencyLines.points !== null);
},
},
};
</script>
包的这个文件(node_modules\gantt-elastic\src\components\Chart\Row\Milestone.vue)
<!--
/**
* @fileoverview Milestone component
* @license MIT
* @author Rafal Pospiech <neuronet.io@gmail.com>
* @package GanttElastic
*/
-->
<template>
<g
class="gantt-elastic__chart-row-bar-wrapper gantt-elastic__chart-row-milestone-wrapper"
:style="{
...root.style['chart-row-bar-wrapper'],
...root.style['chart-row-milestone-wrapper'],
...task.style['chart-row-bar-wrapper']
}"
>
<foreignObject
class="gantt-elastic__chart-expander gantt-elastic__chart-expander--milestone"
:style="{
...root.style['chart-expander'],
...root.style['chart-expander--milestone'],
...task.style['chart-expander']
}"
:x="(task.x - root.state.options.chart.expander.offset - root.state.options.chart.expander.size)-11"
:y="task.y + (root.state.options.row.height - root.state.options.chart.expander.size) / 2"
:width="root.state.options.chart.expander.size"
:height="root.state.options.chart.expander.size"
v-if="displayExpander"
>
<expander :tasks="[task]" :options="root.state.options.chart.expander" type="chart"></expander>
</foreignObject>
<svg
class="gantt-elastic__chart-row-bar gantt-elastic__chart-row-milestone"
:style="{ ...root.style['chart-row-bar'], ...root.style['chart-row-milestone'], ...task.style['chart-row-bar'] }"
:x="task.x"
:y="task.y"
:width="task.width"
:height="task.height"
:viewBox="`0 0 ${task.width} ${task.height}`"
@click="emitEvent('click', $event)"
@mouseenter="emitEvent('mouseenter', $event)"
@mouseover="emitEvent('mouseover', $event)"
@mouseout="emitEvent('mouseout', $event)"
@mousemove="emitEvent('mousemove', $event)"
@mousedown="emitEvent('mousedown', $event)"
@mouseup="emitEvent('mouseup', $event)"
@mousewheel="emitEvent('mousewheel', $event)"
@touchstart="emitEvent('touchstart', $event)"
@touchmove="emitEvent('touchmove', $event)"
@touchend="emitEvent('touchend', $event)"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<clipPath :id="clipPathId">
<polygon :points="getPoints"></polygon>
</clipPath>
</defs>
<polygon
class="gantt-elastic__chart-row-bar-polygon gantt-elastic__chart-row-milestone-polygon"
:style="{
...root.style['chart-row-bar-polygon'],
...root.style['chart-row-milestone-polygon'],
...task.style['base'],
...task.style['chart-row-bar-polygon']
}"
:points="getPoints"
></polygon>
<progress-bar :task="task" :clip-path="'url(#' + clipPathId + ')'"></progress-bar>
</svg>
<chart-text :task="task" v-if="root.state.options.chart.text.display"></chart-text>
</g>
</template>
<script>
import ChartText from '../Text.vue';
import ProgressBar from '../ProgressBar.vue';
import Expander from '../../Expander.vue';
import taskMixin from './Task.mixin.js';
export default {
name: 'Milestone',
components: {
ChartText,
ProgressBar,
Expander
},
inject: ['root'],
props: ['task'],
mixins: [taskMixin],
data() {
return {};
},
computed: {
/**
* Get clip path id
*
* @returns {string}
*/
clipPathId() {
return 'gantt-elastic__milestone-clip-path-' + this.task.id;
},
/**
* Get points
*
* @returns {string}
*/
getPoints() {
const task = this.task;
const fifty = task.height / 2;
let offset = fifty;
if (task.width / 2 - offset < 0) {
offset = task.width / 2;
}
return `0,${fifty}
${offset},0
${task.width - offset},0
${task.width},${fifty}
${task.width - offset},${task.height}
${offset},${task.height}`;
}
}
};
</script>
包的这个文件(node_modules\gantt-elastic\src\components\Chart\Row\Project.vue)
<!--
/**
* @fileoverview Project component
* @license MIT
* @author Rafal Pospiech <neuronet.io@gmail.com>
* @package GanttElastic
*/
-->
<template>
<g
class="gantt-elastic__chart-row-bar-wrapper gantt-elastic__chart-row-project-wrapper"
:style="{
...root.style['chart-row-bar-wrapper'],
...root.style['chart-row-project-wrapper'],
...task.style['chart-row-bar-wrapper']
}"
>
<foreignObject
class="gantt-elastic__chart-expander gantt-elastic__chart-expander--project"
:style="{
...root.style['chart-expander'],
...root.style['chart-expander--project'],
...task.style['chart-expander']
}"
:x="(task.x - root.state.options.chart.expander.offset - root.state.options.chart.expander.size)-11"
:y="task.y + (root.state.options.row.height - root.state.options.chart.expander.size) / 2"
:width="root.state.options.chart.expander.size"
:height="root.state.options.chart.expander.size"
v-if="displayExpander"
>
<expander :tasks="[task]" :options="root.state.options.chart.expander" type="chart"></expander>
</foreignObject>
<svg
class="gantt-elastic__chart-row-bar gantt-elastic__chart-row-project"
:style="{ ...root.style['chart-row-bar'], ...root.style['chart-row-project'], ...task.style['chart-row-bar'] }"
:x="task.x"
:y="task.y"
:width="task.width"
:height="task.height"
:viewBox="`0 0 ${task.width} ${task.height}`"
@click="emitEvent('click', $event)"
@mouseenter="emitEvent('mouseenter', $event)"
@mouseover="emitEvent('mouseover', $event)"
@mouseout="emitEvent('mouseout', $event)"
@mousemove="emitEvent('mousemove', $event)"
@mousedown="emitEvent('mousedown', $event)"
@mouseup="emitEvent('mouseup', $event)"
@mousewheel="emitEvent('mousewheel', $event)"
@touchstart="emitEvent('touchstart', $event)"
@touchmove="emitEvent('touchmove', $event)"
@touchend="emitEvent('touchend', $event)"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<clipPath :id="clipPathId">
<path :d="getPoints"></path>
</clipPath>
</defs>
<path
class="gantt-elastic__chart-row-bar-polygon gantt-elastic__chart-row-project-polygon"
:style="{
...root.style['chart-row-bar-polygon'],
...root.style['chart-row-project-polygon'],
...task.style['base'],
...task.style['chart-row-bar-polygon']
}"
:d="getPoints"
></path>
<progress-bar :task="task" :clip-path="'url(#' + clipPathId + ')'"></progress-bar>
</svg>
<chart-text :task="task" v-if="root.state.options.chart.text.display"></chart-text>
</g>
</template>
<script>
import ChartText from '../Text.vue';
import ProgressBar from '../ProgressBar.vue';
import Expander from '../../Expander.vue';
import taskMixin from './Task.mixin.js';
export default {
name: 'Project',
components: {
ChartText,
ProgressBar,
Expander
},
inject: ['root'],
props: ['task'],
mixins: [taskMixin],
data() {
return {};
},
computed: {
/**
* Get clip path id
*
* @returns {string}
*/
clipPathId() {
return 'gantt-elastic__project-clip-path-' + this.task.id;
},
/**
* Get points
*
* @returns {string}
*/
getPoints() {
const task = this.task;
const bottom = task.height - task.height / 4;
const corner = task.height / 6;
const smallCorner = task.height / 8;
return `M ${smallCorner},0
L ${task.width - smallCorner} 0
L ${task.width} ${smallCorner}
L ${task.width} ${bottom}
L ${task.width - corner} ${task.height}
L ${task.width - corner * 2} ${bottom}
L ${corner * 2} ${bottom}
L ${corner} ${task.height}
L 0 ${bottom}
L 0 ${smallCorner}
Z
`;
},
/**
* Should we display expander?
*
* @returns {boolean}
*/
displayExpander() {
const expander = this.root.state.options.chart.expander;
return expander.display || (expander.displayIfTaskListHidden && !this.root.state.options.taskList.display);
}
}
};
</script>
包的这个文件(node_modules\gantt-elastic\src\components\Chart\Row\Task.vue)
<!--
/**
* @fileoverview Task component
* @license MIT
* @author Rafal Pospiech <neuronet.io@gmail.com>
* @package GanttElastic
*/
-->
<template>
<g
class="gantt-elastic__chart-row-bar-wrapper gantt-elastic__chart-row-task-wrapper"
:style="{
...root.style['chart-row-bar-wrapper'],
...root.style['chart-row-task-wrapper'],
...task.style['chart-row-bar-wrapper']
}"
>
<foreignObject
class="gantt-elastic__chart-expander gantt-elastic__chart-expander--task"
:style="{
...root.style['chart-expander'],
...root.style['chart-expander--task'],
...task.style['chart-expander']
}"
:x="(task.x - root.state.options.chart.expander.offset - root.state.options.chart.expander.size)-11"
:y="task.y + (root.state.options.row.height - root.state.options.chart.expander.size) / 2"
:width="root.state.options.chart.expander.size"
:height="root.state.options.chart.expander.size"
v-if="displayExpander"
>
<expander :tasks="[task]" :options="root.state.options.chart.expander" type="chart"></expander>
</foreignObject>
<svg
class="gantt-elastic__chart-row-bar gantt-elastic__chart-row-task"
:style="{ ...root.style['chart-row-bar'], ...root.style['chart-row-task'], ...task.style['chart-row-bar'] }"
:x="task.x"
:y="task.y"
:width="task.width"
:height="task.height"
:viewBox="`0 0 ${task.width} ${task.height}`"
@click="emitEvent('click', $event)"
@mouseenter="emitEvent('mouseenter', $event)"
@mouseover="emitEvent('mouseover', $event)"
@mouseout="emitEvent('mouseout', $event)"
@mousemove="emitEvent('mousemove', $event)"
@mousedown="emitEvent('mousedown', $event)"
@mouseup="emitEvent('mouseup', $event)"
@mousewheel="emitEvent('mousewheel', $event)"
@touchstart="emitEvent('touchstart', $event)"
@touchmove="emitEvent('touchmove', $event)"
@touchend="emitEvent('touchend', $event)"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<clipPath :id="clipPathId">
<polygon :points="getPoints"></polygon>
</clipPath>
</defs>
<polygon
class="gantt-elastic__chart-row-bar-polygon gantt-elastic__chart-row-task-polygon"
:style="{
...root.style['chart-row-bar-polygon'],
...root.style['chart-row-task-polygon'],
...task.style['base'],
...task.style['chart-row-bar-polygon']
}"
:points="getPoints"
></polygon>
<progress-bar :task="task" :clip-path="'url(#' + clipPathId + ')'"></progress-bar>
</svg>
<chart-text :task="task" v-if="root.state.options.chart.text.display"></chart-text>
</g>
</template>
<script>
import ChartText from '../Text.vue';
import ProgressBar from '../ProgressBar.vue';
import Expander from '../../Expander.vue';
import taskMixin from './Task.mixin.js';
export default {
name: 'Task',
components: {
ChartText,
ProgressBar,
Expander
},
inject: ['root'],
props: ['task'],
mixins: [taskMixin],
data() {
return {};
},
computed: {
/**
* Get clip path id
*
* @returns {string}
*/
clipPathId() {
return 'gantt-elastic__task-clip-path-' + this.task.id;
},
/**
* Get points
*
* @returns {string}
*/
getPoints() {
const task = this.task;
return `0,0 ${task.width},0 ${task.width},${task.height} 0,${task.height}`;
}
}
};
</script>
替换完记得重启项目