├── .gitignore
├── data.php
├── styles
├── css
│ ├── screen.css
│ └── gantti.css
└── scss
│ ├── screen.scss
│ └── gantti.scss
├── readme.mdown
├── index.php
└── lib
├── gantti.php
└── calendar.php
/.gitignore:
--------------------------------------------------------------------------------
1 | .sass-cache/b82a4c54823406b2e3fa108ceb67bf31fad36534/
2 | sass.sh
3 |
4 | styles/css/.DS_Store
5 |
6 | lib/.DS_Store
7 |
--------------------------------------------------------------------------------
/data.php:
--------------------------------------------------------------------------------
1 | 'Project 1',
7 | 'start' => '2012-04-20',
8 | 'end' => '2012-05-12'
9 | );
10 |
11 | $data[] = array(
12 | 'label' => 'Project 2',
13 | 'start' => '2012-04-22',
14 | 'end' => '2012-05-22'
15 | );
16 |
17 | $data[] = array(
18 | 'label' => 'Project 3',
19 | 'start' => '2012-05-25',
20 | 'end' => '2012-06-20'
21 | );
22 |
23 | $data[] = array(
24 | 'label' => 'Project 4',
25 | 'start' => '2012-05-06',
26 | 'end' => '2012-06-17',
27 | 'class' => 'important',
28 | );
29 |
30 | $data[] = array(
31 | 'label' => 'Project 5',
32 | 'start' => '2012-05-11',
33 | 'end' => '2012-06-03',
34 | 'class' => 'urgent',
35 | );
36 |
37 | $data[] = array(
38 | 'label' => 'Project 6',
39 | 'start' => '2012-05-15',
40 | 'end' => '2012-07-03'
41 | );
42 |
43 | $data[] = array(
44 | 'label' => 'Project 7',
45 | 'start' => '2012-06-01',
46 | 'end' => '2012-07-03',
47 | 'class' => 'important',
48 | );
49 |
50 | $data[] = array(
51 | 'label' => 'Project 8',
52 | 'start' => '2012-06-01',
53 | 'end' => '2012-08-05'
54 | );
55 |
56 | $data[] = array(
57 | 'label' => 'Project 9',
58 | 'start' => '2012-07-22',
59 | 'end' => '2012-09-05',
60 | 'class' => 'urgent',
61 | );
62 |
63 | ?>
--------------------------------------------------------------------------------
/styles/css/screen.css:
--------------------------------------------------------------------------------
1 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700);
2 | article, aside, details, figcaption, figure, footer, header, hgroup, nav, section {
3 | display: block; }
4 |
5 | * {
6 | margin: 0;
7 | padding: 0; }
8 |
9 | body {
10 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
11 | font-size: 14px;
12 | line-height: 22px;
13 | background: #fdf6e3;
14 | color: #657b83;
15 | padding: 50px 0; }
16 |
17 | a {
18 | color: #d33682;
19 | text-decoration: none;
20 | border-bottom: 1px solid rgba(0, 0, 0, 0.1); }
21 |
22 | header, article {
23 | width: 500px;
24 | margin: 0 auto;
25 | padding: 50px 20px; }
26 |
27 | figure {
28 | font-size: 12px;
29 | line-height: 18px; }
30 |
31 | h1 {
32 | font-size: 30px;
33 | margin-bottom: 10px;
34 | text-transform: uppercase;
35 | color: #d33682; }
36 |
37 | h2 {
38 | color: #b58900;
39 | font-weight: normal;
40 | margin-bottom: 10px; }
41 |
42 | p {
43 | margin-bottom: 20px; }
44 |
45 | ul li {
46 | list-style: square; }
47 |
48 | article {
49 | padding-bottom: 100px; }
50 |
51 | pre {
52 | font-family: "Monaco", "Courier", monospace;
53 | position: relative;
54 | overflow: auto;
55 | background: #002b36;
56 | color: #93a1a1;
57 | box-shadow: rgba(0, 0, 0, 0.8) 0px 2px 10px inset;
58 | padding: 20px;
59 | font-size: 14px;
60 | line-height: 24px;
61 | margin-bottom: 24px;
62 | border-radius: 3px; }
63 |
64 | pre code {
65 | font-family: "Monaco", "Courier", monospace;
66 | background: none;
67 | padding: 0;
68 | white-space: pre;
69 | box-shadow: none;
70 | border-radius: 0; }
71 |
--------------------------------------------------------------------------------
/styles/scss/screen.scss:
--------------------------------------------------------------------------------
1 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700);
2 |
3 | article, aside, details, figcaption, figure, footer, header, hgroup, nav, section {
4 | display: block;
5 | }
6 |
7 | * {
8 | margin: 0;
9 | padding: 0;
10 | }
11 |
12 | body {
13 | font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
14 | font-size: 14px;
15 | line-height: 22px;
16 | background: #fdf6e3;
17 | color: #657b83;
18 | padding: 50px 0;
19 | }
20 |
21 | a {
22 | color: #d33682;
23 | text-decoration: none;
24 | border-bottom: 1px solid rgba(0,0,0, .1);
25 | }
26 |
27 | header, article {
28 | width: 500px;
29 | margin: 0 auto;
30 | padding: 50px 20px;
31 | }
32 |
33 | figure {
34 | font-size: 12px;
35 | line-height: 18px;
36 | }
37 |
38 | h1 {
39 | font-size: 30px;
40 | margin-bottom: 10px;
41 | text-transform: uppercase;
42 | color: #d33682;
43 | }
44 |
45 | h2 {
46 | color: #b58900;
47 | font-weight: normal;
48 | margin-bottom: 10px;
49 | }
50 |
51 | p {
52 | margin-bottom: 20px;
53 | }
54 |
55 | ul li {
56 | list-style: square;
57 | }
58 |
59 | article {
60 | padding-bottom: 100px;
61 | }
62 |
63 | pre {
64 | font-family: "Monaco", "Courier", monospace;
65 | position: relative;
66 | overflow: auto;
67 | background: #002b36;
68 | color: #93a1a1;
69 | box-shadow: rgba(0,0,0, .8) 0px 2px 10px inset;
70 | padding: 20px;
71 | font-size: 14px;
72 | line-height: 24px;
73 | margin-bottom: 24px;
74 | border-radius: 3px;
75 | }
76 |
77 | pre code {
78 | font-family: "Monaco", "Courier", monospace;
79 | background: none;
80 | padding: 0;
81 | white-space: pre;
82 | box-shadow: none;
83 | border-radius: 0;
84 | }
85 |
--------------------------------------------------------------------------------
/readme.mdown:
--------------------------------------------------------------------------------
1 | # Gantti
2 |
3 | A simple PHP Gantt Class
4 |
5 | ## Features
6 |
7 | - Generates valid HTML5
8 | - Very easy to customize with SASS stylesheet
9 | - Works in all major browsers including IE7, IE8 and IE9
10 | - No javascript required
11 |
12 | ## Demo
13 |
14 |
15 |
16 | ## Usage
17 |
18 | ```php
19 |
20 | 'Project 1',
31 | 'start' => '2012-04-20',
32 | 'end' => '2012-05-12'
33 | );
34 |
35 | $data[] = array(
36 | 'label' => 'Project 2',
37 | 'start' => '2012-04-22',
38 | 'end' => '2012-05-22',
39 | 'class' => 'important',
40 | );
41 |
42 | $data[] = array(
43 | 'label' => 'Project 3',
44 | 'start' => '2012-05-25',
45 | 'end' => '2012-06-20'
46 | 'class' => 'urgent',
47 | );
48 |
49 | $gantti = new Gantti($data, array(
50 | 'title' => 'Demo',
51 | 'cellwidth' => 25,
52 | 'cellheight' => 35
53 | ));
54 |
55 | echo $gantti;
56 |
57 | ?>
58 |
59 | ```
60 |
61 | ## Data
62 |
63 | Data is defined as an associative array (see the example above).
64 |
65 | For each project you get the following options:
66 |
67 | - label: The label will be displayed in the sidebar
68 | - start: The start date. Must be in the following format: YYYY-MM-DD
69 | - end: The end date. Must be in the following format: YYYY-MM-DD
70 | - class: An optional class name. (available by default: important, urgent)
71 |
72 |
73 | ## Options
74 |
75 | ### title (optional, default: false)
76 |
77 | Set an optional title for your gantt diagram here.
78 | It will be displayed in the upper left corner.
79 |
80 | ### cellwidth (optional, default: 40)
81 |
82 | Set the width of all cells.
83 |
84 | ### cellheight (optional, default: 40)
85 |
86 | Set the height of all cells.
87 |
88 | ### today (optional, default: true)
89 |
90 | Show or hide the today marker. It will be displayed by default.
91 |
92 | ## Styles
93 |
94 | The default stylesheet is available as .scss ([SASS](http://sass-lang.com/)) It includes a set of predefined variables, which you can use to adjust the styles very easily.
95 |
96 | ## Colors
97 | The default color theme is an adaption of the wonderful
98 | [Solarized color theme by Ethan Schoonover](http://ethanschoonover.com/solarized)
99 |
100 | ## Author
101 |
102 | Bastian Allgeier
103 |
104 |
105 |
106 | ## License:
107 |
108 | MIT License -
109 |
--------------------------------------------------------------------------------
/styles/css/gantti.css:
--------------------------------------------------------------------------------
1 | /* Sass Variables */
2 | /* gantt styles */
3 | .gantt {
4 | position: relative;
5 | overflow: hidden;
6 | color: #93a1a1;
7 | background: #002b36; }
8 |
9 | .gantt * {
10 | font-weight: normal;
11 | margin: 0;
12 | padding: 0; }
13 |
14 | .gantt li {
15 | list-style: none; }
16 |
17 | /* optional title */
18 | .gantt figcaption {
19 | position: absolute;
20 | top: 25px;
21 | left: 20px;
22 | font-size: 20px;
23 | color: white;
24 | text-transform: uppercase;
25 | letter-spacing: 4px; }
26 |
27 | /* sidebar */
28 | .gantt aside {
29 | position: absolute;
30 | left: 0;
31 | bottom: 0;
32 | top: 0;
33 | width: 199px;
34 | border-right: 1px solid #000b0d;
35 | z-index: 2; }
36 |
37 | .gantt aside:before {
38 | position: absolute;
39 | right: -7px;
40 | pointer-events: none;
41 | width: 7px;
42 | top: 0;
43 | bottom: 0;
44 | content: "";
45 | border-left: 1px solid rgba(255, 255, 255, 0.03);
46 | background: -webkit-linear-gradient(left, rgba(0, 43, 54, 0.7), rgba(0, 43, 54, 0));
47 | background: -moz-linear-gradient(left, rgba(0, 43, 54, 0.7), rgba(0, 43, 54, 0));
48 | background: linear-gradient(left, rgba(0, 43, 54, 0.7), rgba(0, 43, 54, 0));
49 | z-index: 3; }
50 |
51 | .gantt aside .gantt-labels {
52 | border-top: 1px solid #001f27; }
53 |
54 | .gantt aside .gantt-label strong {
55 | display: block;
56 | padding: 0 20px;
57 | color: #93a1a1;
58 | border-bottom: 1px solid #001f27;
59 | overflow: hidden;
60 | text-overflow: ellipsis;
61 | white-space: nowrap; }
62 |
63 | /* data section */
64 | .gantt-data {
65 | position: relative;
66 | overflow-x: scroll;
67 | margin-left: 200px;
68 | white-space: nowrap; }
69 |
70 | /* data section header */
71 | .gantt header .gantt-months {
72 | overflow: hidden; }
73 |
74 | .gantt header .gantt-month {
75 | float: left;
76 | text-align: center; }
77 |
78 | .gantt header .gantt-month strong {
79 | display: block;
80 | border-right: 1px solid #001f27;
81 | border-bottom: 1px solid #001f27; }
82 |
83 | .gantt header .gantt-day span {
84 | text-indent: 0;
85 | text-align: center; }
86 |
87 | .gantt header .gantt-day.today span {
88 | color: white; }
89 |
90 | /* data items */
91 | .gantt-item {
92 | position: relative; }
93 |
94 | .gantt-days {
95 | overflow: hidden; }
96 |
97 | .gantt-day {
98 | float: left; }
99 |
100 | .gantt-day span {
101 | display: block;
102 | border-right: 1px solid #001f27;
103 | border-bottom: 1px solid #001f27;
104 | text-indent: -12000px; }
105 |
106 | .gantt-day.weekend span {
107 | background: #073642; }
108 |
109 | /* data blocks */
110 | .gantt-block {
111 | position: absolute;
112 | top: 0;
113 | z-index: 1;
114 | margin: 4px;
115 | border-radius: 3px;
116 | -webkit-box-shadow: rgba(0, 0, 0, 0.9) 0 2px 6px, rgba(255, 255, 255, 0.2) 0 1px 0 inset;
117 | -moz-box-shadow: rgba(0, 0, 0, 0.9) 0 2px 6px, rgba(255, 255, 255, 0.2) 0 1px 0 inset;
118 | box-shadow: rgba(0, 0, 0, 0.9) 0 2px 6px, rgba(255, 255, 255, 0.2) 0 1px 0 inset;
119 | opacity: .9; }
120 |
121 | .gantt-block-label {
122 | display: block;
123 | color: white;
124 | padding: 5px 10px; }
125 |
126 | /* block colors */
127 | .gantt-block {
128 | background: #268bd2; }
129 |
130 | .gantt-block.important {
131 | background: #b58900; }
132 |
133 | .gantt-block.urgent {
134 | background: #d33682; }
135 |
136 | /* today sign */
137 | .gantt time {
138 | position: absolute;
139 | top: 0;
140 | width: 2px;
141 | background: white;
142 | bottom: 0;
143 | z-index: 1000;
144 | text-indent: -12000px;
145 | -webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 0 10px;
146 | -moz-box-shadow: rgba(0, 0, 0, 0.3) 0 0 10px;
147 | box-shadow: rgba(0, 0, 0, 0.3) 0 0 10px; }
148 |
149 | .gantt time:before {
150 | position: absolute;
151 | content: "";
152 | top: 0;
153 | left: -4px;
154 | border-left: 5px solid transparent;
155 | border-right: 5px solid transparent;
156 | border-top: 5px solid white; }
157 |
158 | /* scrollbar styles */
159 | .gantt ::-webkit-scrollbar {
160 | background: #002b36;
161 | height: 10px; }
162 |
163 | .gantt ::-webkit-scrollbar-thumb {
164 | background: #93a1a1;
165 | -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0 inset;
166 | -moz-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0 inset;
167 | box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0 inset; }
168 |
169 | /* selection styles */
170 | .gantt ::-moz-selection {
171 | background: #fff;
172 | color: #000; }
173 |
174 | .gantt ::selection {
175 | background: #fff;
176 | color: #000; }
177 |
--------------------------------------------------------------------------------
/index.php:
--------------------------------------------------------------------------------
1 | 'Demo',
11 | 'cellwidth' => 25,
12 | 'cellheight' => 35,
13 | 'today' => true
14 | ));
15 |
16 | ?>
17 |
18 |
19 |
20 |
21 |
22 | Mahatma Gantti – A simple PHP Gantt Class
23 |
24 |
25 |
26 |
27 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 | Mahatma Gantti
39 | A simple PHP Gantt Class
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | Download
48 |
49 |
50 | You can download the source for Gantti form Github:
51 | https://github.com/bastianallgeier/gantti
52 |
53 |
54 | Features
55 |
56 |
57 |
58 | Generates valid HTML5
59 | Very easy to customize with SASS stylesheet
60 | Works in all major browsers including IE7, IE8 and IE9
61 | No javascript required
62 |
63 |
64 |
65 | Usage
66 |
67 |
'Project 1',
79 | 'start' => '2012-04-20',
80 | 'end' => '2012-05-12'
81 | );
82 |
83 | \$data[] = array(
84 | 'label' => 'Project 2',
85 | 'start' => '2012-04-22',
86 | 'end' => '2012-05-22',
87 | 'class' => 'important',
88 | );
89 |
90 | \$data[] = array(
91 | 'label' => 'Project 3',
92 | 'start' => '2012-05-25',
93 | 'end' => '2012-06-20'
94 | 'class' => 'urgent',
95 | );
96 |
97 | \$gantti = new Gantti(\$data, array(
98 | 'title' => 'Demo',
99 | 'cellwidth' => 25,
100 | 'cellheight' => 35
101 | ));
102 |
103 | echo \$gantti;
104 |
105 | ?>
106 |
107 | ";
108 |
109 | echo htmlentities(trim($code)); ?>
110 |
111 |
112 | Data
113 |
114 | Data is defined as an associative array (see the example above).
115 |
116 |
117 | For each project you get the following options:
118 |
119 |
120 | label: The label will be displayed in the sidebar
121 | start: The start date. Must be in the following format: YYYY-MM-DD
122 | end: The end date. Must be in the following format: YYYY-MM-DD
123 | class: An optional class name. (available by default: important, urgent)
124 |
125 |
126 |
127 |
128 | Options
129 |
130 | title (optional, default: false)
131 | Set an optional title for your gantt diagram here. It will be displayed in the upper left corner.
132 |
133 | cellwidth (optional, default: 40)
134 | Set the width of all cells.
135 |
136 | cellheight (optional, default: 40)
137 | Set the height of all cells.
138 |
139 | today (optional, default: true)
140 | Show or hide the today marker. It will be displayed by default.
141 |
142 | Styles
143 |
144 |
145 | The default stylesheet is available as .scss (SASS )
146 | It includes a set of predefined variables, which you can use to adjust the styles very easily.
147 |
148 |
149 | You can check out the full SASS file over here:
150 | https://github.com/bastianallgeier/gantti/blob/master/styles/scss/gantti.scss
151 |
152 |
153 |
154 | Colors
155 |
156 | The default color theme is an adaption of the wonderful Solarized color theme by Ethan Schoonover
157 |
158 | Author
159 |
160 |
161 | Bastian Allgeier
162 | http://bastianallgeier.com
163 | Follow me on Twitter
164 |
165 |
166 |
167 | License
168 |
169 | MIT License – http://www.opensource.org/licenses/mit-license.php
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
--------------------------------------------------------------------------------
/styles/scss/gantti.scss:
--------------------------------------------------------------------------------
1 | /* Sass Variables */
2 |
3 | $color-background-dark: #002b36;
4 | $color-background-light: #073642;
5 |
6 | $color-lines: darken($color-background-dark, 3%);
7 | $color-today: #fff;
8 |
9 | $color-text: #93a1a1;
10 | $color-text-today: #fff;
11 | $color-text-label-aside: $color-text;
12 | $color-text-label-block: #fff;
13 | $color-text-title: #fff;
14 |
15 | $color-block-default: #268bd2;
16 | $color-block-important: #b58900;
17 | $color-block-urgent: #d33682;
18 |
19 | $color-scrollbar-back: $color-background-dark;
20 | $color-scrollbar-thumb: #93a1a1;
21 |
22 | $aside-width: 200px;
23 |
24 | /* gantt styles */
25 | .gantt {
26 | position: relative;
27 | overflow: hidden;
28 | color: $color-text;
29 | background: $color-background-dark;
30 | }
31 | .gantt * {
32 | font-weight: normal;
33 | margin: 0;
34 | padding: 0;
35 | }
36 | .gantt li {
37 | list-style: none;
38 | }
39 |
40 | /* optional title */
41 | .gantt figcaption {
42 | position: absolute;
43 | top: 25px;
44 | left: 20px;
45 | font-size: 20px;
46 | color: $color-text-title;
47 | text-transform: uppercase;
48 | letter-spacing: 4px;
49 | }
50 |
51 | /* sidebar */
52 | .gantt aside {
53 | position: absolute;
54 | left: 0;
55 | bottom: 0;
56 | top: 0;
57 | width: $aside-width - 1;
58 | border-right: 1px solid darken($color-lines, 5%);
59 | z-index: 2;
60 | }
61 | .gantt aside:before {
62 | position: absolute;
63 | right: -7px;
64 | pointer-events: none;
65 | width: 7px;
66 | top: 0;
67 | bottom: 0;
68 | content: "";
69 | border-left: 1px solid rgba(255,255,255, .03);
70 | background: -webkit-linear-gradient(left, rgba($color-background-dark,.7), rgba($color-background-dark,0));
71 | background: -moz-linear-gradient(left, rgba($color-background-dark,.7), rgba($color-background-dark,0));
72 | background: linear-gradient(left, rgba($color-background-dark,.7), rgba($color-background-dark,0));
73 | z-index: 3;
74 | }
75 | .gantt aside .gantt-labels {
76 | border-top: 1px solid $color-lines;
77 | }
78 | .gantt aside .gantt-label strong {
79 | display: block;
80 | padding: 0 20px;
81 | color: $color-text-label-aside;
82 | border-bottom: 1px solid $color-lines;
83 | overflow: hidden;
84 | text-overflow: ellipsis;
85 | white-space: nowrap;
86 | }
87 |
88 | /* data section */
89 | .gantt-data {
90 | position: relative;
91 | overflow-x: scroll;
92 | margin-left: $aside-width;
93 | white-space: nowrap;
94 | }
95 |
96 | /* data section header */
97 | .gantt header .gantt-months {
98 | overflow: hidden;
99 | }
100 | .gantt header .gantt-month {
101 | float: left;
102 | text-align: center;
103 | }
104 | .gantt header .gantt-month strong {
105 | display: block;
106 | border-right: 1px solid $color-lines;
107 | border-bottom: 1px solid $color-lines;
108 | }
109 | .gantt header .gantt-day span {
110 | text-indent: 0;
111 | text-align: center;
112 | }
113 | .gantt header .gantt-day.today span {
114 | color: $color-text-today;
115 | }
116 |
117 | /* data items */
118 | .gantt-item {
119 | position: relative;
120 | }
121 | .gantt-days {
122 | overflow: hidden;
123 | }
124 | .gantt-day {
125 | float: left;
126 | }
127 | .gantt-day span {
128 | display: block;
129 | border-right: 1px solid $color-lines;
130 | border-bottom: 1px solid $color-lines;
131 | text-indent: -12000px;
132 | }
133 | .gantt-day.weekend span {
134 | background: $color-background-light;
135 | }
136 |
137 | /* data blocks */
138 | .gantt-block {
139 | position: absolute;
140 | top: 0;
141 | z-index: 1;
142 | margin: 4px;
143 | border-radius: 3px;
144 | -webkit-box-shadow: rgba(0,0,0, .9) 0 2px 6px, rgba(255,255,255, .2) 0 1px 0 inset;
145 | -moz-box-shadow: rgba(0,0,0, .9) 0 2px 6px, rgba(255,255,255, .2) 0 1px 0 inset;
146 | box-shadow: rgba(0,0,0, .9) 0 2px 6px, rgba(255,255,255, .2) 0 1px 0 inset;
147 | opacity: .9;
148 | }
149 | .gantt-block-label {
150 | display: block;
151 | color: $color-text-label-block;
152 | padding: 5px 10px;
153 | }
154 |
155 | /* block colors */
156 | .gantt-block {
157 | background: $color-block-default;
158 | }
159 | .gantt-block.important {
160 | background: $color-block-important;
161 | }
162 | .gantt-block.urgent {
163 | background: $color-block-urgent;
164 | }
165 |
166 | /* today sign */
167 | .gantt time {
168 | position: absolute;
169 | top: 0;
170 | width: 2px;
171 | background: $color-today;
172 | bottom: 0;
173 | z-index: 1000;
174 | text-indent: -12000px;
175 | -webkit-box-shadow: rgba(0,0,0, .3) 0 0 10px;
176 | -moz-box-shadow: rgba(0,0,0, .3) 0 0 10px;
177 | box-shadow: rgba(0,0,0, .3) 0 0 10px;
178 | }
179 | .gantt time:before {
180 | position: absolute;
181 | content: "";
182 | top: 0;
183 | left: -4px;
184 | border-left: 5px solid transparent;
185 | border-right: 5px solid transparent;
186 | border-top: 5px solid $color-today;
187 | }
188 |
189 | /* scrollbar styles */
190 | .gantt ::-webkit-scrollbar {
191 | background: $color-scrollbar-back;
192 | height: 10px;
193 | }
194 | .gantt ::-webkit-scrollbar-thumb {
195 | background: $color-scrollbar-thumb;
196 | -webkit-box-shadow: rgba(255,255,255, .1) 0 1px 0 inset;
197 | -moz-box-shadow: rgba(255,255,255, .1) 0 1px 0 inset;
198 | box-shadow: rgba(255,255,255, .1) 0 1px 0 inset;
199 | }
200 |
201 | /* selection styles */
202 | .gantt ::-moz-selection {
203 | background: #fff;
204 | color: #000;
205 | }
206 | .gantt ::selection {
207 | background: #fff;
208 | color: #000;
209 | }
--------------------------------------------------------------------------------
/lib/gantti.php:
--------------------------------------------------------------------------------
1 | false,
22 | 'cellwidth' => 40,
23 | 'cellheight' => 40,
24 | 'today' => true,
25 | );
26 |
27 | $this->options = array_merge($defaults, $params);
28 | $this->cal = new Calendar();
29 | $this->data = $data;
30 | $this->seconds = 60*60*24;
31 |
32 | $this->cellstyle = 'style="width: ' . $this->options['cellwidth'] . 'px; height: ' . $this->options['cellheight'] . 'px"';
33 |
34 | // parse data and find first and last date
35 | $this->parse();
36 |
37 | }
38 |
39 | function parse() {
40 |
41 | foreach($this->data as $d) {
42 |
43 | $this->blocks[] = array(
44 | 'label' => $d['label'],
45 | 'start' => $start = strtotime($d['start']),
46 | 'end' => $end = strtotime($d['end']),
47 | 'class' => @$d['class']
48 | );
49 |
50 | if(!$this->first || $this->first > $start) $this->first = $start;
51 | if(!$this->last || $this->last < $end) $this->last = $end;
52 |
53 | }
54 |
55 | $this->first = $this->cal->date($this->first);
56 | $this->last = $this->cal->date($this->last);
57 |
58 | $current = $this->first->month();
59 | $lastDay = $this->last->month()->lastDay()->timestamp;
60 |
61 | // build the months
62 | while($current->lastDay()->timestamp <= $lastDay) {
63 | $month = $current->month();
64 | $this->months[] = $month;
65 | foreach($month->days() as $day) {
66 | $this->days[] = $day;
67 | }
68 | $current = $current->next();
69 | }
70 |
71 | }
72 |
73 | function render() {
74 |
75 | $html = array();
76 |
77 | // common styles
78 | $cellstyle = 'style="line-height: ' . $this->options['cellheight'] . 'px; height: ' . $this->options['cellheight'] . 'px"';
79 | $wrapstyle = 'style="width: ' . $this->options['cellwidth'] . 'px"';
80 | $totalstyle = 'style="width: ' . (count($this->days)*$this->options['cellwidth']) . 'px"';
81 | // start the diagram
82 | $html[] = '';
83 |
84 | // set a title if available
85 | if($this->options['title']) {
86 | $html[] = '' . $this->options['title'] . ' ';
87 | }
88 |
89 | // sidebar with labels
90 | $html[] = '';
91 | $html[] = '';
92 | foreach($this->blocks as $i => $block) {
93 | $html[] = '' . $block['label'] . ' ';
94 | }
95 | $html[] = ' ';
96 | $html[] = ' ';
97 |
98 | // data section
99 | $html[] = '';
100 |
101 | // data header section
102 | $html[] = '';
103 |
104 | // months headers
105 | $html[] = '';
106 | foreach($this->months as $month) {
107 | $html[] = '' . $month->name() . ' ';
108 | }
109 | $html[] = ' ';
110 |
111 | // days headers
112 | $html[] = '';
113 | foreach($this->days as $day) {
114 |
115 | $weekend = ($day->isWeekend()) ? ' weekend' : '';
116 | $today = ($day->isToday()) ? ' today' : '';
117 |
118 | $html[] = '' . $day->padded() . ' ';
119 | }
120 | $html[] = ' ';
121 |
122 | // end header
123 | $html[] = ' ';
124 |
125 | // main items
126 | $html[] = '';
127 |
128 | foreach($this->blocks as $i => $block) {
129 |
130 | $html[] = '';
131 |
132 | // days
133 | $html[] = '';
134 | foreach($this->days as $day) {
135 |
136 | $weekend = ($day->isWeekend()) ? ' weekend' : '';
137 | $today = ($day->isToday()) ? ' today' : '';
138 |
139 | $html[] = '' . $day . ' ';
140 | }
141 | $html[] = ' ';
142 |
143 | // the block
144 | $days = (($block['end'] - $block['start']) / $this->seconds);
145 | $offset = (($block['start'] - $this->first->month()->timestamp) / $this->seconds);
146 | $top = round($i * ($this->options['cellheight'] + 1));
147 | $left = round($offset * $this->options['cellwidth']);
148 | $width = round($days * $this->options['cellwidth'] - 9);
149 | $height = round($this->options['cellheight']-8);
150 | $class = ($block['class']) ? ' ' . $block['class'] : '';
151 | $html[] = '' . $days . ' ';
152 | $html[] = ' ';
153 |
154 | }
155 |
156 | $html[] = ' ';
157 |
158 | if($this->options['today']) {
159 |
160 | // today
161 | $today = $this->cal->today();
162 | $offset = (($today->timestamp - $this->first->month()->timestamp) / $this->seconds);
163 | $left = round($offset * $this->options['cellwidth']) + round(($this->options['cellwidth'] / 2) - 1);
164 |
165 | if($today->timestamp > $this->first->month()->firstDay()->timestamp && $today->timestamp < $this->last->month()->lastDay()->timestamp) {
166 | $html[] = 'Today ';
167 | }
168 |
169 | }
170 |
171 | // end data section
172 | $html[] = ' ';
173 |
174 | // end diagram
175 | $html[] = ' ';
176 |
177 | return implode('', $html);
178 |
179 | }
180 |
181 | function __toString() {
182 | return $this->render();
183 | }
184 |
185 | }
186 |
--------------------------------------------------------------------------------
/lib/calendar.php:
--------------------------------------------------------------------------------
1 | _ = $array;
9 | }
10 |
11 | function __toString() {
12 | $result = '';
13 | foreach($this->_ as $date) {
14 | $result .= $date . ' ';
15 | }
16 | return $result;
17 | }
18 |
19 | function rewind() {
20 | reset($this->_);
21 | }
22 |
23 | function current() {
24 | return current($this->_);
25 | }
26 |
27 | function key() {
28 | return key($this->_);
29 | }
30 |
31 | function next() {
32 | return next($this->_);
33 | }
34 |
35 | function prev() {
36 | return prev($this->_);
37 | }
38 |
39 | function valid() {
40 | $key = key($this->_);
41 | $var = ($key !== null && $key !== false);
42 | return $var;
43 | }
44 |
45 | function count() {
46 | return count($this->_);
47 | }
48 |
49 | function first() {
50 | return array_shift($this->_);
51 | }
52 |
53 | function last() {
54 | return array_pop($this->_);
55 | }
56 |
57 | function nth($n) {
58 | $values = array_values($this->_);
59 | return isset($values[$n]) ? $values[$n] : null;
60 | }
61 |
62 | function indexOf($needle) {
63 | return array_search($needle, array_values($this->_));
64 | }
65 |
66 | function toArray() {
67 | return $this->_;
68 | }
69 |
70 | function slice($offset=null, $limit=null) {
71 | if($offset === null && $limit === null) return $this;
72 | return new CalendarIterator(array_slice($this->_, $offset, $limit));
73 | }
74 |
75 | function limit($limit) {
76 | return $this->slice(0, $limit);
77 | }
78 |
79 | }
80 |
81 | class CalendarObj {
82 |
83 | var $yearINT;
84 | var $monthINT;
85 | var $dayINT;
86 | var $hourINT;
87 | var $minuteINT;
88 | var $secondINT;
89 | var $timestamp = 0;
90 |
91 | function __construct($year=false, $month=1, $day=1, $hour=0, $minute=0, $second=0) {
92 |
93 | if(!$year) $year = date('Y');
94 | if(!$month) $month = date('m');
95 | if(!$day) $day = date('d');
96 |
97 | $this->yearINT = intval($year);
98 | $this->monthINT = intval($month);
99 | $this->dayINT = intval($day);
100 | $this->hourINT = intval($hour);
101 | $this->minuteINT = intval($minute);
102 | $this->secondINT = intval($second);
103 |
104 | // convert this to timestamp
105 | $this->timestamp = mktime($hour, $minute, $second, $month, $day, $year);
106 | }
107 |
108 | function year($year=false) {
109 | if(!$year) $year = $this->yearINT;
110 | return new CalendarYear($year, 1, 1, 0, 0, 0);
111 | }
112 |
113 | function month($month=false) {
114 | if(!$month) $month = $this->monthINT;
115 | return new CalendarMonth($this->yearINT, $month, 1, 0, 0, 0);
116 | }
117 |
118 | function day($day=false) {
119 | if(!$day) $day = $this->dayINT;
120 | return new CalendarDay($this->yearINT, $this->monthINT, $day, 0, 0, 0);
121 | }
122 |
123 | function hour($hour=false) {
124 | if(!$hour) $hour = $this->hourINT;
125 | return new CalendarHour($this->yearINT, $this->monthINT, $this->dayINT, $hour, 0, 0);
126 | }
127 |
128 | function minute($minute=false) {
129 | if(!$minute) $minute = $this->minuteINT;
130 | return new CalendarMinute($this->yearINT, $this->monthINT, $this->dayINT, $this->hourINT, $minute, 0);
131 | }
132 |
133 | function second($second=false) {
134 | if(!$second) $second = $this->secondINT;
135 | return new CalendarSecond($this->yearINT, $this->monthINT, $this->dayINT, $this->hourINT, $this->minuteINT, $second);
136 | }
137 |
138 | function timestamp() {
139 | return $this->timestamp;
140 | }
141 |
142 | function __toString() {
143 | return date('Y-m-d H:i:s', $this->timestamp);
144 | }
145 |
146 | function format($format) {
147 | return date($format, $this->timestamp);
148 | }
149 |
150 | function iso() {
151 | return date(DATE_ISO, $this->timestamp);
152 | }
153 |
154 | function cookie() {
155 | return date(DATE_COOKIE, $this->timestamp);
156 | }
157 |
158 | function rss() {
159 | return date(DATE_RSS, $this->timestamp);
160 | }
161 |
162 | function atom() {
163 | return date(DATE_ATOM, $this->timestamp);
164 | }
165 |
166 | function mysql() {
167 | return date('Y-m-d H:i:s', $this->timestamp);
168 | }
169 |
170 | function time() {
171 | return strftime('%T', $this->timestamp);
172 | }
173 |
174 | function ampm() {
175 | return strftime('%p', $this->timestamp);
176 | }
177 |
178 | function modify($string) {
179 | $ts = (is_int($string)) ? $this->timestamp+$string : strtotime($string, $this->timestamp);
180 |
181 | list($year, $month, $day, $hour, $minute, $second) = explode('-', date('Y-m-d-H-i-s', $ts));
182 | return new CalendarDay($year, $month, $day, $hour, $minute, $second);
183 | }
184 |
185 | function plus($string) {
186 | $modifier = (is_int($string)) ? $string : '+' . $string;
187 | return $this->modify($modifier);
188 | }
189 |
190 | function add($string) {
191 | return $this->plus($string);
192 | }
193 |
194 | function minus($string) {
195 | $modifier = (is_int($string)) ? -$string : '-' . $string;
196 | return $this->modify($modifier);
197 | }
198 |
199 | function sub($string) {
200 | return $this->minus($string);
201 | }
202 |
203 | function dmy() {
204 | return $this->format('d.m.Y');
205 | }
206 |
207 | function padded() {
208 | return str_pad($this->int(),2,'0',STR_PAD_LEFT);
209 | }
210 |
211 | }
212 |
213 | class Calendar {
214 |
215 | static $now = 0;
216 |
217 | function __construct() {
218 | Calendar::$now = time();
219 | }
220 |
221 | function years($start, $end) {
222 | $array = array();
223 | foreach(range($start, $end) as $year) {
224 | $array[] = $this->year($year);
225 | }
226 | return new CalendarIterator($array);
227 | }
228 |
229 | function year($year) {
230 | return new CalendarYear($year, 1, 1, 0, 0, 0);
231 | }
232 |
233 | function months($year=false) {
234 | $year = new CalendarYear($year, 1, 1, 0, 0, 0);
235 | return $year->months();
236 | }
237 |
238 | function month($year, $month) {
239 | return new CalendarMonth($year, $month, 1, 0, 0);
240 | }
241 |
242 | function week($year=false, $week=false) {
243 | return new CalendarWeek($year, $week);
244 | }
245 |
246 | function days($year=false) {
247 | $year = new CalendarYear($year);
248 | return $year->days();
249 | }
250 |
251 | function day($year=false, $month=false, $day=false) {
252 | return new CalendarDay($year, $month, $day);
253 | }
254 |
255 | function date() {
256 |
257 | $args = func_get_args();
258 |
259 | if(count($args) > 1) {
260 |
261 | $year = isset($args[0]) ? $args[0] : false;
262 | $month = isset($args[1]) ? $args[1] : 1;
263 | $day = isset($args[2]) ? $args[2] : 1;
264 | $hour = isset($args[3]) ? $args[3] : 0;
265 | $minute = isset($args[4]) ? $args[4] : 0;
266 | $second = isset($args[5]) ? $args[5] : 0;
267 |
268 | } else {
269 |
270 | if(isset($args[0])) {
271 | $ts = (is_int($args[0])) ? $args[0] : strtotime($args[0]);
272 | } else {
273 | $ts = time();
274 | }
275 |
276 | if(!$ts) return false;
277 |
278 | list($year, $month, $day, $hour, $minute, $second) = explode('-', date('Y-m-d-H-i-s', $ts));
279 |
280 | }
281 |
282 | return new CalendarDay($year, $month, $day, $hour, $minute, $second);
283 |
284 | }
285 |
286 | function today() {
287 | return $this->date('today');
288 | }
289 |
290 | function now() {
291 | return $this->today();
292 | }
293 |
294 | function tomorrow() {
295 | return $this->date('tomorrow');
296 | }
297 |
298 | function yesterday() {
299 | return $this->date('yesterday');
300 | }
301 |
302 | }
303 |
304 | class CalendarYear extends CalendarObj {
305 |
306 | function __toString() {
307 | return $this->format('Y');
308 | }
309 |
310 | function int() {
311 | return $this->yearINT;
312 | }
313 |
314 | function months() {
315 | $array = array();
316 | foreach(range(1, 12) as $month) {
317 | $array[] = $this->month($month);
318 | }
319 | return new CalendarIterator($array);
320 | }
321 |
322 | function month($month=1) {
323 | return new CalendarMonth($this->yearINT, $month);
324 | }
325 |
326 | function weeks() {
327 | $array = array();
328 | $weeks = (int)date('W', mktime(0,0,0,12,31,$this->int))+1;
329 | foreach(range(1,$weeks) as $week) {
330 | $array[] = new CalendarWeek($this, $week);
331 | }
332 | return new CalendarIterator($array);
333 | }
334 |
335 | function week($week=1) {
336 | return new CalendarWeek($this, $week);
337 | }
338 |
339 | function countDays() {
340 | return (int)date('z', mktime(0,0,0,12,31,$this->yearINT))+1;
341 | }
342 |
343 | function days() {
344 |
345 | $days = $this->countDays();
346 | $array = array();
347 | $ts = false;
348 |
349 | for($x=0; $x<$days; $x++) {
350 | $ts = (!$ts) ? $this->timestamp : strtotime('tomorrow', $ts);
351 | $month = date('m', $ts);
352 | $day = date('d', $ts);
353 | $array[] = $this->month($month)->day($day);
354 | }
355 |
356 | return new CalendarIterator($array);
357 |
358 | }
359 |
360 | function next() {
361 | return $this->plus('1year')->year();
362 | }
363 |
364 | function prev() {
365 | return $this->minus('1year')->year();
366 | }
367 |
368 | function name() {
369 | return $this->int();
370 | }
371 |
372 | function firstMonday() {
373 | $cal = new Calendar();
374 | return $cal->date(strtotime('first monday of ' . date('Y', $this->timestamp)));
375 | }
376 |
377 | function firstSunday() {
378 | $cal = new Calendar();
379 | return $cal->date(strtotime('first sunday of ' . date('Y', $this->timestamp)));
380 | }
381 |
382 | }
383 |
384 | class CalendarMonth extends CalendarObj {
385 |
386 | function __toString() {
387 | return $this->format('Y-m');
388 | }
389 |
390 | function int() {
391 | return $this->monthINT;
392 | }
393 |
394 | function weeks($force=false) {
395 |
396 | $first = $this->firstDay();
397 | $week = $first->week();
398 |
399 | $currentMonth = $this->int();
400 | $nextMonth = $this->next()->int();
401 |
402 | $max = ($force) ? $force : 6;
403 |
404 | for($x=0; $x<$max; $x++) {
405 |
406 | // make sure not to add weeks without a single day in the same month
407 | if(!$force && $x>0 && $week->firstDay()->month()->int() != $currentMonth) break;
408 |
409 | $array[] = $week;
410 |
411 | // make sure not to add weeks without a single day in the same month
412 | if(!$force && $week->lastDay()->month()->int() != $currentMonth) break;
413 |
414 | $week = $week->next();
415 |
416 | }
417 |
418 | return new CalendarIterator($array);
419 |
420 | }
421 |
422 | function countDays() {
423 | return date('t', $this->timestamp);
424 | }
425 |
426 | function firstDay() {
427 | return new CalendarDay($this->yearINT, $this->monthINT, 1);
428 | }
429 |
430 | function lastDay() {
431 | return new CalendarDay($this->yearINT, $this->monthINT, $this->countDays());
432 | }
433 |
434 | function days() {
435 |
436 | // number of days per month
437 | $days = date('t', $this->timestamp);
438 | $array = array();
439 | $ts = $this->firstDay()->timestamp();
440 |
441 | foreach(range(1, $days) as $day) {
442 | $array[] = $this->day($day);
443 | }
444 |
445 | return new CalendarIterator($array);
446 |
447 | }
448 |
449 | function day($day=1) {
450 | return new CalendarDay($this->yearINT, $this->monthINT, $day);
451 | }
452 |
453 | function next() {
454 | return $this->plus('1month')->month();
455 | }
456 |
457 | function prev() {
458 | return $this->minus('1month')->month();
459 | }
460 |
461 | function name() {
462 | return strftime('%B', $this->timestamp);
463 | }
464 |
465 | function shortname() {
466 | return strftime('%b', $this->timestamp);
467 | }
468 |
469 | }
470 |
471 | class CalendarWeek extends CalendarObj {
472 |
473 | function __toString() {
474 | return $this->firstDay()->format('Y-m-d') . ' - ' . $this->lastDay()->format('Y-m-d');
475 | }
476 |
477 | var $weekINT;
478 |
479 | function int() {
480 | return $this->weekINT;
481 | }
482 |
483 | function __construct($year=false, $week=false) {
484 |
485 | if(!$year) $year = date('Y');
486 | if(!$week) $week = date('W');
487 |
488 | $this->yearINT = intval($year);
489 | $this->weekINT = intval($week);
490 |
491 | $ts = strtotime('Thursday', strtotime($year . 'W' . $this->padded()));
492 | $monday = strtotime('-3days', $ts);
493 |
494 | parent::__construct(date('Y', $monday), date('m', $monday), date('d', $monday), 0, 0, 0);
495 |
496 | }
497 |
498 | function years() {
499 | $array = array();
500 | $array[] = $this->firstDay()->year();
501 | $array[] = $this->lastDay()->year();
502 |
503 | // remove duplicates
504 | $array = array_unique($array);
505 |
506 | return new CalendarIterator($array);
507 | }
508 |
509 | function months() {
510 | $array = array();
511 | $array[] = $this->firstDay()->month();
512 | $array[] = $this->lastDay()->month();
513 |
514 | // remove duplicates
515 | $array = array_unique($array);
516 |
517 | return new CalendarIterator($array);
518 | }
519 |
520 | function firstDay() {
521 | $cal = new Calendar();
522 | return $cal->date($this->timestamp);
523 | }
524 |
525 | function lastDay() {
526 | $first = $this->firstDay();
527 | return $first->plus('6 days');
528 | }
529 |
530 | function days() {
531 |
532 | $day = $this->firstDay();
533 | $array = array();
534 |
535 | for($x=0; $x<7; $x++) {
536 | $array[] = $day;
537 | $day = $day->next();
538 | }
539 |
540 | return new CalendarIterator($array);
541 |
542 | }
543 |
544 | function next() {
545 |
546 | $next = strtotime('Thursday next week', $this->timestamp);
547 | $year = date('Y', $next);
548 | $week = date('W', $next);
549 |
550 | return new CalendarWeek($year, $week);
551 |
552 | }
553 |
554 | function prev() {
555 |
556 | $prev = strtotime('Monday last week', $this->timestamp);
557 | $year = date('Y', $prev);
558 | $week = date('W', $prev);
559 |
560 | return new CalendarWeek($year, $week);
561 |
562 | }
563 |
564 | }
565 |
566 |
567 | class CalendarDay extends CalendarObj {
568 |
569 | function __toString() {
570 | return $this->format('Y-m-d');
571 | }
572 |
573 | function int() {
574 | return $this->dayINT;
575 | }
576 |
577 | function week() {
578 | $week = date('W', $this->timestamp);
579 | $year = ($this->monthINT == 1 && $week > 5) ? $this->year()->prev() : $this->year();
580 | return new CalendarWeek($year->int(), $week);
581 | }
582 |
583 | function next() {
584 | return $this->plus('1day');
585 | }
586 |
587 | function prev() {
588 | return $this->minus('1day');
589 | }
590 |
591 | function weekday() {
592 | return date('N', $this->timestamp);
593 | }
594 |
595 | function name() {
596 | return strftime('%A', $this->timestamp);
597 | }
598 |
599 | function shortname() {
600 | return strftime('%a', $this->timestamp);
601 | }
602 |
603 | function isToday() {
604 | $cal = new Calendar();
605 | return $this == $cal->today();
606 | }
607 |
608 | function isYesterday() {
609 | $cal = new Calendar();
610 | return $this == $cal->yesterday();
611 | }
612 |
613 | function isTomorrow() {
614 | $cal = new Calendar();
615 | return $this == $cal->tomorrow();
616 | }
617 |
618 | function isInThePast() {
619 | return ($this->timestamp < Calendar::$now) ? true : false;
620 | }
621 |
622 | function isInTheFuture() {
623 | return ($this->timestamp > Calendar::$now) ? true : false;
624 | }
625 |
626 | function isWeekend() {
627 | $num = $this->format('w');
628 | return ($num == 6 || $num == 0) ? true : false;
629 | }
630 |
631 | function hours() {
632 |
633 | $obj = $this;
634 | $array = array();
635 |
636 | while($obj->int() == $this->int()) {
637 | $array[] = $obj->hour();
638 | $obj = $obj->plus('1hour');
639 | }
640 |
641 | return new CalendarIterator($array);
642 |
643 | }
644 |
645 | }
646 |
647 | class CalendarHour extends CalendarObj {
648 |
649 | function int() {
650 | return $this->hourINT;
651 | }
652 |
653 | function minutes() {
654 |
655 | $obj = $this;
656 | $array = array();
657 |
658 | while($obj->hourINT == $this->hourINT) {
659 | $array[] = $obj;
660 | $obj = $obj->plus('1minute')->minute();
661 | }
662 |
663 | return new CalendarIterator($array);
664 |
665 | }
666 |
667 | function next() {
668 | return $this->plus('1hour')->hour();
669 | }
670 |
671 | function prev() {
672 | return $this->minus('1hour')->hour();
673 | }
674 |
675 | }
676 |
677 | class CalendarMinute extends CalendarObj {
678 |
679 | function int() {
680 | return $this->minuteINT;
681 | }
682 |
683 | function seconds() {
684 |
685 | $obj = $this;
686 | $array = array();
687 |
688 | while($obj->minuteINT == $this->minuteINT) {
689 | $array[] = $obj;
690 | $obj = $obj->plus('1second')->second();
691 | }
692 |
693 | return new CalendarIterator($array);
694 |
695 | }
696 |
697 | function next() {
698 | return $this->plus('1minute')->minute();
699 | }
700 |
701 | function prev() {
702 | return $this->minus('1minute')->minute();
703 | }
704 |
705 | }
706 |
707 | class CalendarSecond extends CalendarObj {
708 |
709 | function int() {
710 | return $this->secondINT;
711 | }
712 |
713 | function next() {
714 | return $this->plus('1second')->second();
715 | }
716 |
717 | function prev() {
718 | return $this->minus('1second')->second();
719 | }
720 |
721 | }
722 |
723 |
724 |
725 |
--------------------------------------------------------------------------------