Compare commits
5 Commits
release/0.
...
master
Author | SHA1 | Date | |
---|---|---|---|
06f0a9b4ac | |||
0b43e4ecd7 | |||
|
e279321367 | ||
|
fee71b651c | ||
|
d05d22afe7 |
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "LiteRyzJS/Project",
|
"name": "LiteRyzJS/Project",
|
||||||
"version": "0.2.0.508",
|
"version": "0.2.1.114",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"sass": "^1.77.8",
|
"sass": "^1.77.8",
|
||||||
|
204
src/project/background-canvas.js
Normal file
204
src/project/background-canvas.js
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
import Canvas from '../references/canvas.js';
|
||||||
|
|
||||||
|
|
||||||
|
class BackgroundCanvas extends Canvas {
|
||||||
|
Options = null;
|
||||||
|
Debug = false;
|
||||||
|
|
||||||
|
StartDate = new Date();
|
||||||
|
Duration = 30;
|
||||||
|
StartOfWeek = 1;
|
||||||
|
RowCount = 8;
|
||||||
|
|
||||||
|
|
||||||
|
constructor(el) {
|
||||||
|
super(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get HeaderRow1Rectangle() {
|
||||||
|
return {
|
||||||
|
X: 0,
|
||||||
|
Y: 0,
|
||||||
|
W: this.Width,
|
||||||
|
H: (this.Options.HeaderRow.Height[0] - this.Options.BorderWidth)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get HeaderRow2Rectangle() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
return {
|
||||||
|
X: 0,
|
||||||
|
Y: this.Options.HeaderRow.Height[0],
|
||||||
|
W: this.Width,
|
||||||
|
H: (this.Options.HeaderRow.Height[1] - this.Options.BorderWidth)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get HeaderHeight() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
return a.Options.HeaderRow.Height[0] + a.Options.HeaderRow.Height[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Load(startDate, duration, startOfWeek, rowCount) {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
a.StartDate = new Date(startDate);
|
||||||
|
a.Duration = duration;
|
||||||
|
a.StartOfWeek = startOfWeek; // 1 = Monday
|
||||||
|
a.RowCount = rowCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
Invalidate() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
if (a.Options == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.StartDate == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.#drawChartHeader();
|
||||||
|
a.#drawColumnLayout();
|
||||||
|
a.#drawRowLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
#drawChartHeader() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
const displayDays = a.Duration + 2;
|
||||||
|
|
||||||
|
if (a.Debug) {
|
||||||
|
a.DrawRectangle(a.HeaderRow1Rectangle, "red", {});
|
||||||
|
a.DrawRectangle(a.HeaderRow2Rectangle, "orange", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
let startDate = new Date(a.StartDate);
|
||||||
|
startDate.addDays(-1);
|
||||||
|
|
||||||
|
// Draw horizontal line under months
|
||||||
|
a.#drawHorizontalLine(a.Options.HeaderRow.Height[0]);
|
||||||
|
|
||||||
|
// Draw vertical lines for dates
|
||||||
|
for (let i=1; i<displayDays; i++) {
|
||||||
|
a.DrawVerticalLine((a.Options.DayWidth * i), (a.Options.HeaderRow.Height[0] + a.Options.BorderWidth), (a.Options.HeaderRow.Height[1] - a.Options.BorderWidth), a.Options.BorderColour, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw horizontal line under dates
|
||||||
|
a.#drawHorizontalLine(a.HeaderHeight);
|
||||||
|
|
||||||
|
// Write dates
|
||||||
|
for (let i=0; i<displayDays; i++) {
|
||||||
|
const date = Date.addDays(startDate, i);
|
||||||
|
const x = (a.Options.DayWidth * i);
|
||||||
|
|
||||||
|
// Draw month
|
||||||
|
if (date.getDate() == 1) {
|
||||||
|
const size = a.MeasureText(a.Options.DateFont, "#");
|
||||||
|
const monthPoint = {
|
||||||
|
X: (x + 2),
|
||||||
|
Y: Math.half(a.Options.HeaderRow.Height[0] - size.H)
|
||||||
|
};
|
||||||
|
|
||||||
|
a.DrawText(monthPoint.X, monthPoint.Y, date.toCString("MMMM"), a.Options.DateFont, a.Options.DateForeColour);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw day
|
||||||
|
const dateRectangle = {
|
||||||
|
X: x,
|
||||||
|
Y: a.Options.HeaderRow.Height[0],
|
||||||
|
W: a.Options.DayWidth - a.Options.BorderWidth,
|
||||||
|
H: (a.Options.HeaderRow.Height[1] - a.Options.BorderWidth)
|
||||||
|
};
|
||||||
|
|
||||||
|
a.FillText(dateRectangle, date.getDate(), a.Options.DateFont, a.Options.DateForeColour);
|
||||||
|
|
||||||
|
if (a.Debug) {
|
||||||
|
a.DrawRectangle(dateRectangle, "red", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#drawColumnLayout() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
const height = a.Height;
|
||||||
|
const displayDays = a.Duration + 2;
|
||||||
|
|
||||||
|
let startDate = new Date(a.StartDate);
|
||||||
|
startDate.addDays(-1);
|
||||||
|
|
||||||
|
// Write dates
|
||||||
|
for (let i=0; i<displayDays; i++) {
|
||||||
|
const date = Date.addDays(startDate, i);
|
||||||
|
const x = (a.Options.DayWidth * i);
|
||||||
|
|
||||||
|
const dateRectangle = {
|
||||||
|
X: x,
|
||||||
|
Y: a.HeaderHeight,
|
||||||
|
W: a.Options.DayWidth - a.Options.BorderWidth,
|
||||||
|
H: height - a.Options.BorderWidth
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fill background for Saturday and Sunday
|
||||||
|
if (date.getDay() == 6) {
|
||||||
|
a.DrawRectangle(dateRectangle, a.Options.Column.SatColour, { FillColour: a.Options.Column.SatColour });
|
||||||
|
} else if (date.getDay() == 0) {
|
||||||
|
a.DrawRectangle(dateRectangle, a.Options.Column.SunColour, { FillColour: a.Options.Column.SunColour });
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw vertical date lines
|
||||||
|
if (a.StartOfWeek == date.getDay()) {
|
||||||
|
if (a.Options.ShowStartDayOfWeekLine) {
|
||||||
|
a.DrawVerticalLine(dateRectangle.X, a.HeaderHeight, dateRectangle.H, a.Options.BorderColour, {});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (a.Options.ShowDateLines) {
|
||||||
|
a.DrawVerticalLine(dateRectangle.X, a.HeaderHeight, dateRectangle.H, a.Options.BorderColour, { LineDash: a.Options.BorderDashPattern });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#drawRowLayout() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
for (let i=0; i<a.RowCount; i++) {
|
||||||
|
const rowRectangle = {
|
||||||
|
X: 0,
|
||||||
|
Y: (a.HeaderHeight + (a.Options.Row.Height * i)),
|
||||||
|
W: a.Width,
|
||||||
|
H: (a.Options.Row.Height - a.Options.BorderWidth)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (a.Options.ShowRowStripes) {
|
||||||
|
if ((i % 2) == 1) {
|
||||||
|
a.DrawRectangle(rowRectangle, a.Options.Row.BackColour, { FillColour: a.Options.Row.BackColour });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.Options.ShowRowLines) {
|
||||||
|
a.DrawHorizontalLine(0, (rowRectangle.Y + a.Options.Row.Height), rowRectangle.W, a.Options.BorderColour, { LineDash: a.Options.BorderDashPattern });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#drawHorizontalLine(y) {
|
||||||
|
const a = this;
|
||||||
|
const width = a.Width;
|
||||||
|
|
||||||
|
a.DrawHorizontalLine(0, y, width, this.Options.BorderColour);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default BackgroundCanvas;
|
80
src/project/flourish-canvas.js
Normal file
80
src/project/flourish-canvas.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
import Canvas from '../references/canvas.js';
|
||||||
|
|
||||||
|
|
||||||
|
class FlourishCanvas extends Canvas {
|
||||||
|
Options = null;
|
||||||
|
Debug = false;
|
||||||
|
|
||||||
|
XPos = -1
|
||||||
|
|
||||||
|
|
||||||
|
constructor(el) {
|
||||||
|
super(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get HeaderHeight() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
return a.Options.HeaderRow.Height[0] + a.Options.HeaderRow.Height[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Load() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
a.el.addEventListener('mousemove', function (e) {
|
||||||
|
// Hottracking
|
||||||
|
if (a.Options.EnableHotTracking) {
|
||||||
|
const point = { X: e.offsetX, Y: e.offsetY };
|
||||||
|
|
||||||
|
if (a.Debug) {
|
||||||
|
console.log(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.XPos = point.X;
|
||||||
|
|
||||||
|
a.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
a.el.addEventListener('mouseout', function (e) {
|
||||||
|
a.XPos = -1;
|
||||||
|
|
||||||
|
a.Invalidate();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Invalidate() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
if (a.Options == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Clear();
|
||||||
|
|
||||||
|
if (a.XPos < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.#drawVerticalLine(a.XPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
#drawVerticalLine(x) {
|
||||||
|
const a = this;
|
||||||
|
const h = this.Height - a.HeaderHeight;
|
||||||
|
|
||||||
|
if (a.Options.HotTrackLine.Width > 1) {
|
||||||
|
x += Math.half(a.Options.HotTrackLine.Width);
|
||||||
|
}
|
||||||
|
|
||||||
|
a.DrawVerticalLine(x, a.HeaderHeight, h, a.Options.HotTrackLine.Colour, { LineWidth: a.Options.HotTrackLine.Width });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default FlourishCanvas;
|
157
src/project/foreground-canvas.js
Normal file
157
src/project/foreground-canvas.js
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
import Canvas from '../references/canvas.js';
|
||||||
|
|
||||||
|
|
||||||
|
class ForegroundCanvas extends Canvas {
|
||||||
|
Options = null;
|
||||||
|
Debug = false;
|
||||||
|
|
||||||
|
StartDate = new Date();
|
||||||
|
Tasks = [];
|
||||||
|
|
||||||
|
|
||||||
|
constructor(el) {
|
||||||
|
super(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get HeaderHeight() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
return a.Options.HeaderRow.Height[0] + a.Options.HeaderRow.Height[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Load(startDate, tasks) {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
a.StartDate = new Date(startDate);
|
||||||
|
a.Tasks = tasks;
|
||||||
|
}
|
||||||
|
|
||||||
|
Invalidate() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
if (a.Options == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.StartDate == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.#drawTasks();
|
||||||
|
a.#drawConnectorLines();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#drawTasks() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
for (let i=0; i<a.Tasks.length; i++) {
|
||||||
|
let style = a.Options.Row.Task;
|
||||||
|
|
||||||
|
if (a.Tasks[i].IsCollated == true) {
|
||||||
|
style = a.Options.Row.CollatedTask;
|
||||||
|
} else if (a.Tasks[i].CollatedTaskID != null) {
|
||||||
|
style = a.Options.Row.ChildTask;
|
||||||
|
} else if (a.Tasks[i].PredecessorTaskID == null) {
|
||||||
|
style = a.Options.Row.OrphanTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rectangle = a.#getTaskRectangle(a.Tasks[i], style);
|
||||||
|
|
||||||
|
if (a.Tasks[i].Duration <= 0) {
|
||||||
|
a.DrawDiamond(rectangle, style.BorderColour, { FillColour: style.FillColour });
|
||||||
|
} else {
|
||||||
|
a.DrawRectangle(rectangle, style.BorderColour, { FillColour: style.FillColour });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#drawConnectorLines() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
for (let i=0; i<a.Tasks.length; i++) {
|
||||||
|
if (a.Tasks[i].PredecessorTaskID == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.Tasks[i].PredecessorTaskID == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const style = ((a.Tasks[i].IsCollated == true) ? a.Options.Row.CollatedTask : a.Options.Row.Task);
|
||||||
|
const rectangle = a.#getTaskRectangle(a.Tasks[i], style);
|
||||||
|
const paddingX = (a.Options.Row.CollatedTask.Height + a.Options.BorderWidth);
|
||||||
|
const offsetX = (rectangle.X + paddingX);
|
||||||
|
|
||||||
|
const predecessorTask = a.Tasks.first("ID", a.Tasks[i].PredecessorTaskID);
|
||||||
|
if (predecessorTask == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const predecessorStyle = ((predecessorTask.IsCollated == true) ? a.Options.Row.CollatedTask : a.Options.Row.Task);
|
||||||
|
const predecessorRectangle = a.#getTaskRectangle(predecessorTask, predecessorStyle);
|
||||||
|
|
||||||
|
let points = [];
|
||||||
|
points.push({ X: (predecessorRectangle.X + predecessorRectangle.W), Y: (predecessorRectangle.Y + Math.half(predecessorRectangle.H)) });
|
||||||
|
points.push({ X: offsetX, Y: (predecessorRectangle.Y + Math.half(predecessorRectangle.H)) });
|
||||||
|
|
||||||
|
points.push({ X: offsetX, Y: (rectangle.Y - paddingX) });
|
||||||
|
points.push({ X: offsetX, Y: rectangle.Y });
|
||||||
|
|
||||||
|
a.DrawLines(points, a.Options.Line.Colour, { LineWidth: a.Options.Line.Width });
|
||||||
|
|
||||||
|
const arrowRectangle = {
|
||||||
|
X: (offsetX - Math.half(a.Options.Line.ArrowSize)),
|
||||||
|
Y: (rectangle.Y - a.Options.Line.ArrowSize),
|
||||||
|
W: a.Options.Line.ArrowSize,
|
||||||
|
H: a.Options.Line.ArrowSize
|
||||||
|
}
|
||||||
|
|
||||||
|
a.DrawArrowS(arrowRectangle, a.Options.Line.Colour, { FillColour: a.Options.Line.Colour });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#getTaskRectangle(task, style) {
|
||||||
|
const a = this;
|
||||||
|
const i = (task.Order - 1);
|
||||||
|
|
||||||
|
const rowRectangle = {
|
||||||
|
X: 0,
|
||||||
|
Y: (a.HeaderHeight + (a.Options.Row.Height * i)),
|
||||||
|
W: a.Width,
|
||||||
|
H: (a.Options.Row.Height - a.Options.BorderWidth)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (a.Debug) {
|
||||||
|
a.DrawRectangle(rowRectangle, "red", {});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (task.Duration <= 0) {
|
||||||
|
let result = {
|
||||||
|
X: (a.Options.DayWidth * (Date.diffDays(a.StartDate, task.StartDate) + 1)),
|
||||||
|
Y: (a.HeaderHeight + (a.Options.Row.Height * i) + Math.half(rowRectangle.H - style.Height)),
|
||||||
|
W: style.Height,
|
||||||
|
H: style.Height
|
||||||
|
};
|
||||||
|
|
||||||
|
result.X += Math.half(a.Options.DayWidth - (style.Height + a.Options.BorderWidth));
|
||||||
|
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
X: (a.Options.DayWidth * (Date.diffDays(a.StartDate, task.StartDate) + 1)),
|
||||||
|
Y: (a.HeaderHeight + (a.Options.Row.Height * i) + Math.half(rowRectangle.H - style.Height)),
|
||||||
|
W: (a.Options.DayWidth * task.Duration),
|
||||||
|
H: style.Height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default ForegroundCanvas;
|
58
src/project/gantt-chart-options.js
Normal file
58
src/project/gantt-chart-options.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
class GanttChartOptions {
|
||||||
|
DayWidth = 24;
|
||||||
|
HeaderRow = {
|
||||||
|
Height: [ 20, 20 ]
|
||||||
|
};
|
||||||
|
Row = {
|
||||||
|
Height: 28,
|
||||||
|
BackColour: "rgba(235, 235, 235, 0.3)",
|
||||||
|
Task: {
|
||||||
|
Height: 14,
|
||||||
|
BorderColour: "#555555",
|
||||||
|
FillColour: "#D8EEDB"
|
||||||
|
},
|
||||||
|
OrphanTask: {
|
||||||
|
Height: 14,
|
||||||
|
BorderColour: "#555555",
|
||||||
|
FillColour: "#9CC2E6"
|
||||||
|
},
|
||||||
|
ChildTask: {
|
||||||
|
Height: 14,
|
||||||
|
BorderColour: "#555555",
|
||||||
|
FillColour: "#FFF5C1"
|
||||||
|
},
|
||||||
|
CollatedTask: {
|
||||||
|
Height: 6,
|
||||||
|
BorderColour: "#555555",
|
||||||
|
FillColour: "#555555"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Column = {
|
||||||
|
SatColour: "rgba(233, 237, 239, 0.8)",
|
||||||
|
SunColour: "rgba(233, 237, 239, 0.9)"
|
||||||
|
};
|
||||||
|
Line = {
|
||||||
|
Colour: "#555555",
|
||||||
|
Width: 1,
|
||||||
|
ArrowSize: 5
|
||||||
|
};
|
||||||
|
HotTrackLine = {
|
||||||
|
Colour: "#D04437",
|
||||||
|
Width: 1
|
||||||
|
};
|
||||||
|
DateFont = "7pt sans-serif";
|
||||||
|
DateForeColour = "#636363";
|
||||||
|
BorderWidth = 1;
|
||||||
|
BorderColour = "#B8B8B8";
|
||||||
|
BorderDashPattern = [1, 1];
|
||||||
|
EnableHotTracking = true;
|
||||||
|
MinimumRowCount = 6;
|
||||||
|
ShowDateLines = true;
|
||||||
|
ShowStartDayOfWeekLine = true;
|
||||||
|
ShowRowLines = true;
|
||||||
|
ShowRowStripes = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default GanttChartOptions;
|
@ -1,20 +1,29 @@
|
|||||||
import Canvas from '../references/canvas.js';
|
import GanttChartOptions from './gantt-chart-options.js';
|
||||||
|
|
||||||
|
import CanvasContainer from '../references/canvas-container.js';
|
||||||
|
import BackgroundCanvas from './background-canvas.js';
|
||||||
|
import ForegroundCanvas from './foreground-canvas.js';
|
||||||
|
import FlourishCanvas from './flourish-canvas.js';
|
||||||
|
|
||||||
import './project.scss';
|
import './project.scss';
|
||||||
|
|
||||||
|
|
||||||
class GanttChart {
|
class GanttChart {
|
||||||
|
Options = null;
|
||||||
|
CanvasContainer = null;
|
||||||
|
|
||||||
|
#debug = false;
|
||||||
|
Tasks = [];
|
||||||
|
StartDate = null;
|
||||||
|
Duration = 30;
|
||||||
|
StartOfWeek = 1;
|
||||||
|
|
||||||
|
|
||||||
constructor(el, options) {
|
constructor(el, options) {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
a.Canvas = new Canvas(el);
|
a.Options = Object.assign(new GanttChartOptions(), options);
|
||||||
a.Options = Object.assign(a.DefaultOptions, options);
|
a.CanvasContainer = new CanvasContainer(el);
|
||||||
|
|
||||||
a.Debug = false;
|
|
||||||
a.Tasks = [];
|
|
||||||
a.StartDate = null;
|
|
||||||
a.Duration = 30;
|
|
||||||
a.StartOfWeek = 1;
|
|
||||||
|
|
||||||
a.#initialiseComponents();
|
a.#initialiseComponents();
|
||||||
}
|
}
|
||||||
@ -22,136 +31,102 @@ class GanttChart {
|
|||||||
#initialiseComponents() {
|
#initialiseComponents() {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
if (!a.Canvas.el.classList.contains("literyzjs-project")) {
|
// Add background canvas layer
|
||||||
a.Canvas.el.classList.add("literyzjs-project");
|
const layer1 = a.CanvasContainer.AddLayer();
|
||||||
}
|
|
||||||
|
|
||||||
if (a.Canvas.FlowContainer.classList.contains("border")) {
|
const backCanvasLayer = new BackgroundCanvas(layer1);
|
||||||
a.Canvas.FlowContainer.classList.remove("border");
|
backCanvasLayer.Options = a.Options;
|
||||||
}
|
|
||||||
|
|
||||||
if (!a.Canvas.FlowContainer.classList.contains("gantt-chart")) {
|
a.CanvasContainer.Layer.push(backCanvasLayer);
|
||||||
a.Canvas.FlowContainer.classList.add("gantt-chart");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Add foreground canvas layer
|
||||||
|
const layer2 = a.CanvasContainer.AddLayer();
|
||||||
|
|
||||||
|
const foreCanvasLayer = new ForegroundCanvas(layer2);
|
||||||
|
foreCanvasLayer.Options = a.Options;
|
||||||
|
|
||||||
|
a.CanvasContainer.Layer.push(foreCanvasLayer);
|
||||||
|
|
||||||
|
// Add flourish canvas layer
|
||||||
|
const layer3 = a.CanvasContainer.AddLayer();
|
||||||
|
|
||||||
|
const flourishCanvasLayer = new FlourishCanvas(layer3);
|
||||||
|
flourishCanvasLayer.Options = a.Options;
|
||||||
|
|
||||||
|
a.CanvasContainer.Layer.push(flourishCanvasLayer);
|
||||||
|
|
||||||
|
// Invalidate every canvas
|
||||||
|
a.CanvasContainer.Invalidate();
|
||||||
|
|
||||||
|
Document.removeClass(a.CanvasContainer.FlowContainer, "border");
|
||||||
|
Document.addClass(a.CanvasContainer.FlowContainer, "gantt-chart");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
get DefaultOptions() {
|
|
||||||
return {
|
|
||||||
DayWidth: 24,
|
|
||||||
HeaderRow: {
|
|
||||||
Height: [ 20, 21 ]
|
|
||||||
},
|
|
||||||
Row: {
|
|
||||||
Height: 28,
|
|
||||||
BackColour: "rgba(235, 235, 235, 0.3)",
|
|
||||||
Task: {
|
|
||||||
Height: 14,
|
|
||||||
BorderColour: "#555555",
|
|
||||||
FillColour: "#D8EEDB"
|
|
||||||
},
|
|
||||||
OrphanTask: {
|
|
||||||
Height: 14,
|
|
||||||
BorderColour: "#555555",
|
|
||||||
FillColour: "#9CC2E6"
|
|
||||||
},
|
|
||||||
ChildTask: {
|
|
||||||
Height: 14,
|
|
||||||
BorderColour: "#555555",
|
|
||||||
FillColour: "#FFF5C1"
|
|
||||||
},
|
|
||||||
CollatedTask: {
|
|
||||||
Height: 6,
|
|
||||||
BorderColour: "#555555",
|
|
||||||
FillColour: "#555555"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Column: {
|
|
||||||
SatColour: "rgba(233, 237, 239, 0.8)",
|
|
||||||
SunColour: "rgba(233, 237, 239, 0.9)",
|
|
||||||
},
|
|
||||||
Line: {
|
|
||||||
Colour: "#555555",
|
|
||||||
Width: 1,
|
|
||||||
ArrowSize: 5
|
|
||||||
},
|
|
||||||
DateFont: "7pt sans-serif",
|
|
||||||
DateForeColour: "#636363",
|
|
||||||
BorderWidth: 1,
|
|
||||||
BorderColour: "#B8B8B8",
|
|
||||||
BorderDashPattern: [1, 1],
|
|
||||||
MinimumRowCount: 6,
|
|
||||||
ShowDateLines: true,
|
|
||||||
ShowStartDayOfWeekLine: true,
|
|
||||||
ShowRowLines: true,
|
|
||||||
ShowRowStripes: true
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get HeaderRow1Rectangle() {
|
|
||||||
return {
|
|
||||||
X: 0,
|
|
||||||
Y: 0,
|
|
||||||
W: this.Canvas.Width,
|
|
||||||
H: (this.Options.HeaderRow.Height[0] - this.Options.BorderWidth)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get HeaderRow2Rectangle() {
|
|
||||||
const a = this;
|
|
||||||
|
|
||||||
return {
|
|
||||||
X: 0,
|
|
||||||
Y: this.Options.HeaderRow.Height[0],
|
|
||||||
W: this.Canvas.Width,
|
|
||||||
H: (this.Options.HeaderRow.Height[1] - this.Options.BorderWidth)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get HeaderHeight() {
|
get HeaderHeight() {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
return a.Options.HeaderRow.Height[0] + a.Options.HeaderRow.Height[1];
|
return a.Options.HeaderRow.Height[0] + a.Options.HeaderRow.Height[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get Debug() {
|
||||||
|
return this.#debug;
|
||||||
|
}
|
||||||
|
|
||||||
|
set Debug(value) {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
a.#debug = value;
|
||||||
|
|
||||||
|
a.CanvasContainer.Layer.forEach(e => {
|
||||||
|
if (typeof(e.Debug) == "undefined") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
e.Debug = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Clear() {
|
Clear() {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
a.Canvas.Clear();
|
a.CanvasContainer.Clear();
|
||||||
|
|
||||||
a.StartDate = new Date();
|
a.StartDate = new Date();
|
||||||
a.Duration = 30;
|
a.Duration = 30;
|
||||||
a.StartOfWeek = 1; // 1 = Monday
|
a.StartOfWeek = 1; // 1 = Monday
|
||||||
a.Tasks = [];
|
a.Tasks = [];
|
||||||
|
|
||||||
|
// Invalidate canvas (background, foreground)
|
||||||
|
a.CanvasContainer.Layer[0].Load(new Date(), a.Duration, a.StartOfWeek, a.Tasks.length);
|
||||||
|
a.CanvasContainer.Layer[1].Load(new Date(), a.Tasks);
|
||||||
|
a.CanvasContainer.Layer[2].Load();
|
||||||
|
|
||||||
a.Invalidate();
|
a.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
Invalidate() {
|
Invalidate() {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
a.Canvas.Clear();
|
a.CanvasContainer.Clear();
|
||||||
|
|
||||||
const width = ((a.Duration + 2) * a.Options.DayWidth);
|
const width = ((a.Duration + 2) * a.Options.DayWidth);
|
||||||
const height = (Math.max(a.Tasks.length, a.Options.MinimumRowCount) * a.Options.Row.Height) + a.HeaderHeight;
|
const height = (Math.max(a.Tasks.length, a.Options.MinimumRowCount) * a.Options.Row.Height) + a.HeaderHeight;
|
||||||
|
|
||||||
a.Canvas.Size = { W: width, H: height };
|
a.CanvasContainer.Size = {
|
||||||
|
W: width,
|
||||||
|
H: height
|
||||||
|
};
|
||||||
|
|
||||||
a.Canvas.Invalidate();
|
a.CanvasContainer.Invalidate();
|
||||||
|
|
||||||
a.#drawChartHeader();
|
|
||||||
a.#drawColumnLayout();
|
|
||||||
a.#drawRowLayout();
|
|
||||||
a.#drawTasks();
|
|
||||||
a.#drawConnectorLines();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Load(project) {
|
Load(project) {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
a.Canvas.Clear();
|
a.CanvasContainer.Clear();
|
||||||
|
|
||||||
if (project == null) {
|
if (project == null) {
|
||||||
return;
|
return;
|
||||||
@ -162,244 +137,14 @@ class GanttChart {
|
|||||||
a.StartOfWeek = project.Project.StartOfWeek;
|
a.StartOfWeek = project.Project.StartOfWeek;
|
||||||
a.Tasks = project.ExportTasks();
|
a.Tasks = project.ExportTasks();
|
||||||
|
|
||||||
|
// Invalidate canvas (background, foreground)
|
||||||
|
a.CanvasContainer.Layer[0].Load(new Date(project.StartDate), project.Duration, project.Project.StartOfWeek, a.Tasks.length);
|
||||||
|
a.CanvasContainer.Layer[1].Load(new Date(project.StartDate), a.Tasks);
|
||||||
|
a.CanvasContainer.Layer[2].Load();
|
||||||
|
|
||||||
a.Invalidate();
|
a.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
#drawChartHeader() {
|
|
||||||
const a = this;
|
|
||||||
|
|
||||||
const displayDays = a.Duration + 2;
|
|
||||||
|
|
||||||
if (a.Debug) {
|
|
||||||
a.Canvas.DrawRectangle(a.HeaderRow1Rectangle, "red", {});
|
|
||||||
a.Canvas.DrawRectangle(a.HeaderRow2Rectangle, "orange", {});
|
|
||||||
}
|
|
||||||
|
|
||||||
let startDate = new Date(a.StartDate);
|
|
||||||
startDate.addDays(-1);
|
|
||||||
|
|
||||||
// Draw horizontal line under months
|
|
||||||
a.#drawHorizontalLine(a.Options.HeaderRow.Height[0]);
|
|
||||||
|
|
||||||
// Draw vertical lines for dates
|
|
||||||
for (let i=1; i<displayDays; i++) {
|
|
||||||
a.Canvas.DrawVerticalLine((a.Options.DayWidth * i), (a.Options.HeaderRow.Height[0] + a.Options.BorderWidth), (a.Options.HeaderRow.Height[1] - a.Options.BorderWidth), a.Options.BorderColour, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw horizontal line under dates
|
|
||||||
a.#drawHorizontalLine(a.HeaderHeight);
|
|
||||||
|
|
||||||
// Write dates
|
|
||||||
for (let i=0; i<displayDays; i++) {
|
|
||||||
const date = Date.addDays(startDate, i);
|
|
||||||
const x = (a.Options.DayWidth * i);
|
|
||||||
|
|
||||||
// Draw month
|
|
||||||
if (date.getDate() == 1) {
|
|
||||||
const size = a.Canvas.MeasureText(a.Options.DateFont, "#");
|
|
||||||
const monthPoint = {
|
|
||||||
X: (x + 2),
|
|
||||||
Y: Math.half(a.Options.HeaderRow.Height[0] - size.H)
|
|
||||||
};
|
|
||||||
|
|
||||||
a.Canvas.DrawText(monthPoint.X, monthPoint.Y, date.toCString("MMMM"), a.Options.DateFont, a.Options.DateForeColour);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw day
|
|
||||||
const dateRectangle = {
|
|
||||||
X: x,
|
|
||||||
Y: a.Options.HeaderRow.Height[0],
|
|
||||||
W: a.Options.DayWidth - a.Options.BorderWidth,
|
|
||||||
H: (a.Options.HeaderRow.Height[1] - a.Options.BorderWidth)
|
|
||||||
};
|
|
||||||
|
|
||||||
a.Canvas.FillText(dateRectangle, date.getDate(), a.Options.DateFont, a.Options.DateForeColour);
|
|
||||||
|
|
||||||
if (a.Debug) {
|
|
||||||
a.Canvas.DrawRectangle(dateRectangle, "red", {});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#drawColumnLayout() {
|
|
||||||
const a = this;
|
|
||||||
|
|
||||||
const height = a.Canvas.Height;
|
|
||||||
const displayDays = a.Duration + 2;
|
|
||||||
|
|
||||||
let startDate = new Date(a.StartDate);
|
|
||||||
startDate.addDays(-1);
|
|
||||||
|
|
||||||
// Write dates
|
|
||||||
for (let i=0; i<displayDays; i++) {
|
|
||||||
const date = Date.addDays(startDate, i);
|
|
||||||
const x = (a.Options.DayWidth * i);
|
|
||||||
|
|
||||||
const dateRectangle = {
|
|
||||||
X: x,
|
|
||||||
Y: a.HeaderHeight,
|
|
||||||
W: a.Options.DayWidth - a.Options.BorderWidth,
|
|
||||||
H: height - a.Options.BorderWidth
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fill background for Saturday and Sunday
|
|
||||||
if (date.getDay() == 6) {
|
|
||||||
a.Canvas.DrawRectangle(dateRectangle, a.Options.Column.SatColour, { FillColour: a.Options.Column.SatColour });
|
|
||||||
} else if (date.getDay() == 0) {
|
|
||||||
a.Canvas.DrawRectangle(dateRectangle, a.Options.Column.SunColour, { FillColour: a.Options.Column.SunColour });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw vertical date lines
|
|
||||||
if (a.StartOfWeek == date.getDay()) {
|
|
||||||
if (a.Options.ShowStartDayOfWeekLine) {
|
|
||||||
a.Canvas.DrawVerticalLine(dateRectangle.X, a.HeaderHeight, dateRectangle.H, a.Options.BorderColour, {});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (a.Options.ShowDateLines) {
|
|
||||||
a.Canvas.DrawVerticalLine(dateRectangle.X, a.HeaderHeight, dateRectangle.H, a.Options.BorderColour, { LineDash: a.Options.BorderDashPattern });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#drawRowLayout() {
|
|
||||||
const a = this;
|
|
||||||
|
|
||||||
for (let i=0; i<a.Tasks.length; i++) {
|
|
||||||
const rowRectangle = {
|
|
||||||
X: 0,
|
|
||||||
Y: (a.HeaderHeight + (a.Options.Row.Height * i)),
|
|
||||||
W: a.Canvas.Width,
|
|
||||||
H: (a.Options.Row.Height - a.Options.BorderWidth)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (a.Options.ShowRowStripes) {
|
|
||||||
if ((i % 2) == 1) {
|
|
||||||
a.Canvas.DrawRectangle(rowRectangle, a.Options.Row.BackColour, { FillColour: a.Options.Row.BackColour });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.Options.ShowRowLines) {
|
|
||||||
a.Canvas.DrawHorizontalLine(0, (rowRectangle.Y + a.Options.Row.Height), rowRectangle.W, a.Options.BorderColour, { LineDash: a.Options.BorderDashPattern });
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#drawTasks() {
|
|
||||||
const a = this;
|
|
||||||
|
|
||||||
for (let i=0; i<a.Tasks.length; i++) {
|
|
||||||
let style = a.Options.Row.Task;
|
|
||||||
|
|
||||||
if (a.Tasks[i].IsCollated == true) {
|
|
||||||
style = a.Options.Row.CollatedTask;
|
|
||||||
} else if (a.Tasks[i].CollatedTaskID != null) {
|
|
||||||
style = a.Options.Row.ChildTask;
|
|
||||||
} else if (a.Tasks[i].PredecessorTaskID == null) {
|
|
||||||
style = a.Options.Row.OrphanTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
const rectangle = a.#getTaskRectangle(a.Tasks[i], style);
|
|
||||||
|
|
||||||
if (a.Tasks[i].Duration <= 0) {
|
|
||||||
a.Canvas.DrawDiamond(rectangle, style.BorderColour, { FillColour: style.FillColour });
|
|
||||||
} else {
|
|
||||||
a.Canvas.DrawRectangle(rectangle, style.BorderColour, { FillColour: style.FillColour });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#drawConnectorLines() {
|
|
||||||
const a = this;
|
|
||||||
|
|
||||||
for (let i=0; i<a.Tasks.length; i++) {
|
|
||||||
if (a.Tasks[i].PredecessorTaskID == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.Tasks[i].PredecessorTaskID == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const style = ((a.Tasks[i].IsCollated == true) ? a.Options.Row.CollatedTask : a.Options.Row.Task);
|
|
||||||
const rectangle = a.#getTaskRectangle(a.Tasks[i], style);
|
|
||||||
const paddingX = (a.Options.Row.CollatedTask.Height + a.Options.BorderWidth);
|
|
||||||
const offsetX = (rectangle.X + paddingX);
|
|
||||||
|
|
||||||
const predecessorTask = a.Tasks.first("ID", a.Tasks[i].PredecessorTaskID);
|
|
||||||
if (predecessorTask == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const predecessorStyle = ((predecessorTask.IsCollated == true) ? a.Options.Row.CollatedTask : a.Options.Row.Task);
|
|
||||||
const predecessorRectangle = a.#getTaskRectangle(predecessorTask, predecessorStyle);
|
|
||||||
|
|
||||||
let points = [];
|
|
||||||
points.push({ X: (predecessorRectangle.X + predecessorRectangle.W), Y: (predecessorRectangle.Y + Math.half(predecessorRectangle.H)) });
|
|
||||||
points.push({ X: offsetX, Y: (predecessorRectangle.Y + Math.half(predecessorRectangle.H)) });
|
|
||||||
|
|
||||||
points.push({ X: offsetX, Y: (rectangle.Y - paddingX) });
|
|
||||||
points.push({ X: offsetX, Y: rectangle.Y });
|
|
||||||
|
|
||||||
a.Canvas.DrawLines(points, a.Options.Line.Colour, { LineWidth: a.Options.Line.Width });
|
|
||||||
|
|
||||||
const arrowRectangle = {
|
|
||||||
X: (offsetX - Math.half(a.Options.Line.ArrowSize)),
|
|
||||||
Y: (rectangle.Y - a.Options.Line.ArrowSize),
|
|
||||||
W: a.Options.Line.ArrowSize,
|
|
||||||
H: a.Options.Line.ArrowSize
|
|
||||||
}
|
|
||||||
|
|
||||||
a.Canvas.DrawArrowS(arrowRectangle, a.Options.Line.Colour, { FillColour: a.Options.Line.Colour });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#drawHorizontalLine(y) {
|
|
||||||
const a = this;
|
|
||||||
const width = a.Canvas.Width;
|
|
||||||
|
|
||||||
a.Canvas.DrawHorizontalLine(0, y, width, this.Options.BorderColour);
|
|
||||||
}
|
|
||||||
|
|
||||||
#getTaskRectangle(task, style) {
|
|
||||||
const a = this;
|
|
||||||
const i = (task.Order - 1);
|
|
||||||
|
|
||||||
const rowRectangle = {
|
|
||||||
X: 0,
|
|
||||||
Y: (a.HeaderHeight + (a.Options.Row.Height * i)),
|
|
||||||
W: a.Canvas.Width,
|
|
||||||
H: (a.Options.Row.Height - a.Options.BorderWidth)
|
|
||||||
};
|
|
||||||
|
|
||||||
if (a.Debug) {
|
|
||||||
a.Canvas.DrawRectangle(rowRectangle, "red", {});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task.Duration <= 0) {
|
|
||||||
let result = {
|
|
||||||
X: (a.Options.DayWidth * (Date.diffDays(a.StartDate, task.StartDate) + 1)),
|
|
||||||
Y: (a.HeaderHeight + (a.Options.Row.Height * i) + Math.half(rowRectangle.H - style.Height)),
|
|
||||||
W: style.Height,
|
|
||||||
H: style.Height
|
|
||||||
};
|
|
||||||
|
|
||||||
result.X += Math.half(a.Options.DayWidth - (style.Height + a.Options.BorderWidth));
|
|
||||||
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
X: (a.Options.DayWidth * (Date.diffDays(a.StartDate, task.StartDate) + 1)),
|
|
||||||
Y: (a.HeaderHeight + (a.Options.Row.Height * i) + Math.half(rowRectangle.H - style.Height)),
|
|
||||||
W: (a.Options.DayWidth * task.Duration),
|
|
||||||
H: style.Height
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ class Project {
|
|||||||
const a = this;
|
const a = this;
|
||||||
const _options = Object.assign(a.DefaultOptions, options);
|
const _options = Object.assign(a.DefaultOptions, options);
|
||||||
|
|
||||||
a.Debug = true;
|
a.Debug = false;
|
||||||
a.Project = _options;
|
a.Project = _options;
|
||||||
a.Tasks = [];
|
a.Tasks = [];
|
||||||
}
|
}
|
||||||
|
@ -117,17 +117,25 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.gantt-chart {
|
}
|
||||||
border-color: #B8B8B8;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 1px;
|
|
||||||
overflow: hidden;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: #CDCDCD #F0F0F0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.gantt-chart.scroll-x {
|
|
||||||
|
.gantt-chart {
|
||||||
|
border-color: #B8B8B8;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
overflow: hidden;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #CDCDCD #F0F0F0;
|
||||||
|
|
||||||
|
|
||||||
|
&.scroll-x {
|
||||||
overflow-x: scroll !important;
|
overflow-x: scroll !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
canvas {
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
229
src/references/canvas-container.js
Normal file
229
src/references/canvas-container.js
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
class CanvasContainer {
|
||||||
|
|
||||||
|
constructor(el) {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
a.el = el;
|
||||||
|
|
||||||
|
a.Layer = [];
|
||||||
|
a.BorderWidth = 2;
|
||||||
|
a.ScrollbarWidth = 11;
|
||||||
|
a.Padding = {
|
||||||
|
Top: 0,
|
||||||
|
Right: 0,
|
||||||
|
Bottom: 0,
|
||||||
|
Left: 0
|
||||||
|
};
|
||||||
|
a.EnableDock = true;
|
||||||
|
|
||||||
|
a.#initialiseComponents();
|
||||||
|
}
|
||||||
|
|
||||||
|
#initialiseComponents() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
a.ClearLayers();
|
||||||
|
|
||||||
|
// a.Invalidate();
|
||||||
|
// a.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
get FlowContainer() {
|
||||||
|
return this.el.getElementsByTagName("div")[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
get Height() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
if (a.Layer.length <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Document.getHeight(a.Layer[0].el);
|
||||||
|
}
|
||||||
|
|
||||||
|
set Height(value) {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
// if (a.el != null) {
|
||||||
|
// a.el.style.height = value + "px";
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (a.FlowContainer != null) {
|
||||||
|
a.FlowContainer.style.height = value + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (a.CanvasContainer != null) {
|
||||||
|
// a.CanvasContainer.style.height = value + "px";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (a.CanvasContext != null) {
|
||||||
|
// a.CanvasContext.canvas.height = value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
a.Layer.forEach((e, i) => {
|
||||||
|
e.Height = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get Width() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
if (a.Layer.length <= 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Document.getWidth(a.Layer[0].el);
|
||||||
|
}
|
||||||
|
|
||||||
|
set Width(value) {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
// if (a.el != null) {
|
||||||
|
// a.el.style.width = value + "px";
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (a.FlowContainer != null) {
|
||||||
|
a.FlowContainer.style.width = value + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (a.CanvasContainer != null) {
|
||||||
|
// a.CanvasContainer.style.width = value + "px";
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (a.CanvasContext != null) {
|
||||||
|
// a.CanvasContext.canvas.width = value;
|
||||||
|
// }
|
||||||
|
|
||||||
|
a.Layer.forEach((e, i) => {
|
||||||
|
e.Width = value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get Size() {
|
||||||
|
return {
|
||||||
|
W: this.Width,
|
||||||
|
H: this.Height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
set Size(value) {
|
||||||
|
this.Width = value.W;
|
||||||
|
this.Height = value.H;
|
||||||
|
}
|
||||||
|
|
||||||
|
get ClientRectangle() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
return {
|
||||||
|
X: a.Padding.Left,
|
||||||
|
Y: a.Padding.Top,
|
||||||
|
W: (a.Width - (a.Padding.Left + a.Padding.Right)),
|
||||||
|
H: (a.Height - (a.Padding.Top + a.Padding.Bottom))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get Rectangle() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
return {
|
||||||
|
X: 0,
|
||||||
|
Y: 0,
|
||||||
|
W: a.Width,
|
||||||
|
H: a.Height
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Clear() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
// if (a.CanvasContext == null) {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// a.CanvasContext.clearRect(0, 0, a.CanvasContext.canvas.width, a.CanvasContext.canvas.height);
|
||||||
|
|
||||||
|
a.Layer.forEach((e, i) => {
|
||||||
|
e.Clear();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearLayers() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
if (a.el != null) {
|
||||||
|
a.el.innerHTML = "<div class='border'></div>";
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Layer = [];
|
||||||
|
|
||||||
|
a.Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLayer() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
if (a.el == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const divList = a.el.getElementsByTagName("div");
|
||||||
|
if (divList.length <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add another canvas element
|
||||||
|
Document.appendHtml(divList[0], "canvas");
|
||||||
|
|
||||||
|
const canvasList = a.el.getElementsByTagName("canvas");
|
||||||
|
const result = canvasList[(canvasList.length - 1)];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Invalidate() {
|
||||||
|
const a = this;
|
||||||
|
|
||||||
|
if (a.EnableDock) {
|
||||||
|
a.FlowContainer.style.width = "100%";
|
||||||
|
}
|
||||||
|
|
||||||
|
const w = (a.Layer.length <= 0 ? 0 : Document.getWidth(a.Layer[0].el));
|
||||||
|
const h = (a.Layer.length <= 0 ? 0 : Document.getHeight(a.Layer[0].el));
|
||||||
|
|
||||||
|
if (w > (Document.getWidth(a.FlowContainer) + (a.BorderWidth * 2))) {
|
||||||
|
a.FlowContainer.classList.add("scroll-x");
|
||||||
|
a.FlowContainer.style.height = (h + a.ScrollbarWidth) + "px";
|
||||||
|
} else {
|
||||||
|
a.FlowContainer.classList.remove("scroll-x");
|
||||||
|
a.FlowContainer.style.height = h + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
a.Layer.forEach(e => {
|
||||||
|
if (typeof(e.Invalidate) != "undefined") {
|
||||||
|
e.Invalidate();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let offsetTop = 0;
|
||||||
|
|
||||||
|
a.Layer.forEach((e, i) => {
|
||||||
|
if (i <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Correct positon because of position-relative to keep container overflow working
|
||||||
|
const h = Document.getHeight(a.Layer[(i - 1)].el);
|
||||||
|
|
||||||
|
offsetTop += h;
|
||||||
|
|
||||||
|
a.Layer[i].el.style.top = "-" + offsetTop + "px";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default CanvasContainer;
|
@ -1,19 +1,10 @@
|
|||||||
class Canvas {
|
class Canvas {
|
||||||
|
|
||||||
constructor(el) {
|
constructor(el) {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
a.el = el;
|
a.el = el;
|
||||||
|
|
||||||
a.BorderWidth = 2;
|
a.BorderWidth = 2;
|
||||||
a.ScrollbarWidth = 11;
|
|
||||||
a.Padding = {
|
|
||||||
Top: 0,
|
|
||||||
Right: 0,
|
|
||||||
Bottom: 0,
|
|
||||||
Left: 0
|
|
||||||
};
|
|
||||||
a.EnableDock = true;
|
|
||||||
|
|
||||||
a.#initialiseComponents();
|
a.#initialiseComponents();
|
||||||
}
|
}
|
||||||
@ -25,48 +16,30 @@ class Canvas {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.el.innerHTML = "<div class='border'><canvas></canvas></div>";
|
|
||||||
|
|
||||||
a.Invalidate();
|
|
||||||
a.Clear();
|
a.Clear();
|
||||||
|
a.Invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
get FlowContainer() {
|
|
||||||
return this.el.getElementsByTagName("div")[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
get CanvasContainer() {
|
|
||||||
return this.FlowContainer.getElementsByTagName("canvas")[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
get CanvasContext() {
|
get CanvasContext() {
|
||||||
return this.CanvasContainer.getContext("2d");
|
return this.el.getContext("2d");
|
||||||
}
|
}
|
||||||
|
|
||||||
get Height() {
|
get Height() {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
if (a.CanvasContainer == null) {
|
if (a.el == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.#getHeight(a.CanvasContainer);
|
return Document.getHeight(a.el);
|
||||||
}
|
}
|
||||||
|
|
||||||
set Height(value) {
|
set Height(value) {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
// if (a.el != null) {
|
if (a.el != null) {
|
||||||
// a.el.style.height = value + "px";
|
a.el.style.height = value + "px";
|
||||||
// }
|
|
||||||
|
|
||||||
if (a.FlowContainer != null) {
|
|
||||||
a.FlowContainer.style.height = value + "px";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.CanvasContainer != null) {
|
|
||||||
a.CanvasContainer.style.height = value + "px";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.CanvasContext != null) {
|
if (a.CanvasContext != null) {
|
||||||
@ -77,26 +50,18 @@ class Canvas {
|
|||||||
get Width() {
|
get Width() {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
if (a.CanvasContainer == null) {
|
if (a.el == null) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return a.#getWidth(a.CanvasContainer);
|
return Document.getWidth(a.el);
|
||||||
}
|
}
|
||||||
|
|
||||||
set Width(value) {
|
set Width(value) {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
// if (a.el != null) {
|
if (a.el != null) {
|
||||||
// a.el.style.width = value + "px";
|
a.el.style.width = value + "px";
|
||||||
// }
|
|
||||||
|
|
||||||
if (a.FlowContainer != null) {
|
|
||||||
a.FlowContainer.style.width = value + "px";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.CanvasContainer != null) {
|
|
||||||
a.CanvasContainer.style.width = value + "px";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.CanvasContext != null) {
|
if (a.CanvasContext != null) {
|
||||||
@ -116,17 +81,6 @@ class Canvas {
|
|||||||
this.Height = value.H;
|
this.Height = value.H;
|
||||||
}
|
}
|
||||||
|
|
||||||
get ClientRectangle() {
|
|
||||||
const a = this;
|
|
||||||
|
|
||||||
return {
|
|
||||||
X: a.Padding.Left,
|
|
||||||
Y: a.Padding.Top,
|
|
||||||
W: (a.Width - (a.Padding.Left + a.Padding.Right)),
|
|
||||||
H: (a.Height - (a.Padding.Top + a.Padding.Bottom))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
get Rectangle() {
|
get Rectangle() {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
@ -466,23 +420,6 @@ class Canvas {
|
|||||||
a.CanvasContext.fillText(text, x, y);
|
a.CanvasContext.fillText(text, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
Invalidate() {
|
|
||||||
const a = this;
|
|
||||||
|
|
||||||
if (a.EnableDock) {
|
|
||||||
a.FlowContainer.style.width = "100%";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (a.#getWidth(a.CanvasContainer) > (a.#getWidth(a.FlowContainer) + (a.BorderWidth * 2))) {
|
|
||||||
a.FlowContainer.classList.add("scroll-x");
|
|
||||||
a.FlowContainer.style.height = (a.#getHeight(a.CanvasContainer) + a.ScrollbarWidth) + "px";
|
|
||||||
} else {
|
|
||||||
a.FlowContainer.classList.remove("scroll-x");
|
|
||||||
a.FlowContainer.style.height = a.#getHeight(a.CanvasContainer) + "px";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MeasureText(font, value) {
|
MeasureText(font, value) {
|
||||||
const a = this;
|
const a = this;
|
||||||
|
|
||||||
@ -500,30 +437,6 @@ class Canvas {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#getWidth(el) {
|
|
||||||
if (el == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(el) == "undefined") {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (el.offsetWidth || el.innerWidth || el.clientWidth);
|
|
||||||
}
|
|
||||||
|
|
||||||
#getHeight(el) {
|
|
||||||
if (el == null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof(el) == "undefined") {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (el.offsetHeight || el.innerHeight || el.clientHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user