Browse files

first version

  • Loading branch information...
0 parents commit 9196f812c58fbe2f0fdae66f66d74c2310af602d @bastianallgeier committed Jul 24, 2012
Showing with 1,679 additions and 0 deletions.
  1. +2 −0 .gitignore
  2. +2 −0 .gitignore.php
  3. +63 −0 data.php
  4. +170 −0 index.php
  5. +724 −0 lib/calendar.php
  6. +185 −0 lib/gantti.php
  7. +173 −0 styles/css/gantti.css
  8. +70 −0 styles/css/screen.css
  9. +206 −0 styles/scss/gantti.scss
  10. +84 −0 styles/scss/screen.scss
2 .gitignore
@@ -0,0 +1,2 @@
+.sass-cache/b82a4c54823406b2e3fa108ceb67bf31fad36534/
+sass.sh
2 .gitignore.php
@@ -0,0 +1,2 @@
+.sass-cache
+sass.sh
63 data.php
@@ -0,0 +1,63 @@
+<?php
+
+$data = array();
+
+$data[] = array(
+ 'label' => 'Project 1',
+ 'start' => '2012-04-20',
+ 'end' => '2012-05-12'
+);
+
+$data[] = array(
+ 'label' => 'Project 2',
+ 'start' => '2012-04-22',
+ 'end' => '2012-05-22'
+);
+
+$data[] = array(
+ 'label' => 'Project 3',
+ 'start' => '2012-05-25',
+ 'end' => '2012-06-20'
+);
+
+$data[] = array(
+ 'label' => 'Project 4',
+ 'start' => '2012-05-06',
+ 'end' => '2012-06-17',
+ 'class' => 'important',
+);
+
+$data[] = array(
+ 'label' => 'Project 5',
+ 'start' => '2012-05-11',
+ 'end' => '2012-06-03',
+ 'class' => 'urgent',
+);
+
+$data[] = array(
+ 'label' => 'Project 6',
+ 'start' => '2012-05-15',
+ 'end' => '2012-07-03'
+);
+
+$data[] = array(
+ 'label' => 'Project 7',
+ 'start' => '2012-06-01',
+ 'end' => '2012-07-03',
+ 'class' => 'important',
+);
+
+$data[] = array(
+ 'label' => 'Project 8',
+ 'start' => '2012-06-01',
+ 'end' => '2012-08-05'
+);
+
+$data[] = array(
+ 'label' => 'Project 9',
+ 'start' => '2012-07-22',
+ 'end' => '2012-09-05',
+ 'class' => 'urgent',
+);
+
+?>
170 index.php
@@ -0,0 +1,170 @@
+<?php
+
+require('lib/gantti.php');
+require('data.php');
+
+date_default_timezone_set('UTC');
+setlocale(LC_ALL, 'en_US');
+
+$gantti = new Gantti($data, array(
+ 'title' => 'Demo',
+ 'cellwidth' => 25,
+ 'cellheight' => 35,
+ 'today' => true
+));
+
+?>
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+
+ <title>Mahatma Gantti</title>
+ <meta charset="utf-8" />
+
+ <link rel="stylesheet" href="styles/css/screen.css" />
+ <link rel="stylesheet" href="styles/css/gantti.css" />
+
+ <!--[if lt IE 9]>
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+</head>
+
+<body>
+
+<header>
+
+<h1>Mahatma Gantti</h1>
+<h2>A simple PHP Gantt Class</h2>
+
+</header>
+
+<?php echo $gantti ?>
+
+<article>
+
+<h2>Download</h2>
+
+<p>
+ You can download the source for Gantti form Github:<br />
+ <a href="https://github.com/bastianallgeier/gantti"><strong>https://github.com/bastianallgeier/gantti</strong></a>
+</p>
+
+<h2>Features</h2>
+
+<p>
+ <ul>
+ <li>Generates valid HTML5</li>
+ <li>Very easy to customize with SASS stylesheet</li>
+ <li>Works in all major browsers including IE7, IE8 and IE9</li>
+ <li>No javascript required</li>
+ </ul>
+</p>
+
+<h2>Usage</h2>
+
+<p><pre><code><?php $code = "
+<?php
+
+require('lib/gantti.php');
+
+date_default_timezone_set('UTC');
+setlocale(LC_ALL, 'en_US');
+
+\$data = array();
+
+\$data[] = array(
+ 'label' => 'Project 1',
+ 'start' => '2012-04-20',
+ 'end' => '2012-05-12'
+);
+
+\$data[] = array(
+ 'label' => 'Project 2',
+ 'start' => '2012-04-22',
+ 'end' => '2012-05-22',
+ 'class' => 'important',
+);
+
+\$data[] = array(
+ 'label' => 'Project 3',
+ 'start' => '2012-05-25',
+ 'end' => '2012-06-20'
+ 'class' => 'urgent',
+);
+
+\$gantti = new Gantti(\$data, array(
+ 'title' => 'Demo',
+ 'cellwidth' => 25,
+ 'cellheight' => 35
+));
+
+echo \$gantti;
+
+?>
+
+";
+
+echo htmlentities(trim($code)); ?>
+</pre></code></p>
+
+<h2>Data</h2>
+
+<p>Data is defined as an associative array (see the example above).</p>
+
+<p>
+ For each project you get the following options:
+
+ <ul>
+ <li>label: The label will be displayed in the sidebar</li>
+ <li>start: The start date. Must be in the following format: YYYY-MM-DD</li>
+ <li>end: The end date. Must be in the following format: YYYY-MM-DD</li>
+ <li>class: An optional class name. (available by default: important, urgent)</li>
+ </ul>
+
+</p>
+
+<h2>Options</h2>
+
+<h3>title (optional, default: false)</h3>
+<p>Set an optional title for your gantt diagram here. <br />It will be displayed in the upper left corner. </p>
+
+<h3>cellwidth (optional, default: 40)</h3>
+<p>Set the width of all cells. </p>
+
+<h3>cellheight (optional, default: 40)</h3>
+<p>Set the height of all cells. </p>
+
+<h3>today (optional, default: true)</h3>
+<p>Show or hide the today marker. It will be displayed by default.</p>
+
+<h2>Styles</h2>
+
+<p>
+The default stylesheet is available as .scss (<a href="http://sass-lang.com/">SASS</a>)
+It includes a set of predefined variables, which you can use to adjust the styles very easily.
+</p>
+
+<h2>Colors</h2>
+
+<p>The default color theme is an adaption of the wonderful <br /><a href="http://ethanschoonover.com/solarized">Solarized color theme by Ethan Schoonover</a></p>
+
+<h2>Author</h2>
+
+<p>
+Bastian Allgeier<br />
+<a href="http://bastianallgeier.com">http://bastianallgeier.com</a><br />
+<a href="http://twitter.com/bastianallgeier">Follow me on Twitter</a>
+
+</p>
+
+<h2>License</h2>
+
+MIT License – <a href="http://www.opensource.org/licenses/mit-license.php">http://www.opensource.org/licenses/mit-license.php</a>
+
+</article>
+
+</body>
+
+</html>
724 lib/calendar.php
@@ -0,0 +1,724 @@
+<?php
+
+class CalendarIterator implements Iterator {
+
+ private $_ = array();
+
+ public function __construct($array=array()) {
+ $this->_ = $array;
+ }
+
+ function __toString() {
+ $result = '';
+ foreach($this->_ as $date) {
+ $result .= $date . '<br />';
+ }
+ return $result;
+ }
+
+ function rewind() {
+ reset($this->_);
+ }
+
+ function current() {
+ return current($this->_);
+ }
+
+ function key() {
+ return key($this->_);
+ }
+
+ function next() {
+ return next($this->_);
+ }
+
+ function prev() {
+ return prev($this->_);
+ }
+
+ function valid() {
+ $key = key($this->_);
+ $var = ($key !== null && $key !== false);
+ return $var;
+ }
+
+ function count() {
+ return count($this->_);
+ }
+
+ function first() {
+ return array_shift($this->_);
+ }
+
+ function last() {
+ return array_pop($this->_);
+ }
+
+ function nth($n) {
+ $values = array_values($this->_);
+ return isset($values[$n]) ? $values[$n] : null;
+ }
+
+ function indexOf($needle) {
+ return array_search($needle, array_values($this->_));
+ }
+
+ function toArray() {
+ return $this->_;
+ }
+
+ function slice($offset=null, $limit=null) {
+ if($offset === null && $limit === null) return $this;
+ return new CalendarIterator(array_slice($this->_, $offset, $limit));
+ }
+
+ function limit($limit) {
+ return $this->slice(0, $limit);
+ }
+
+}
+
+class CalendarObj {
+
+ var $yearINT;
+ var $monthINT;
+ var $dayINT;
+ var $hourINT;
+ var $minuteINT;
+ var $secondINT;
+ var $timestamp = 0;
+
+ function __construct($year=false, $month=1, $day=1, $hour=0, $minute=0, $second=0) {
+
+ if(!$year) $year = date('Y');
+ if(!$month) $month = date('m');
+ if(!$day) $day = date('d');
+
+ $this->yearINT = intval($year);
+ $this->monthINT = intval($month);
+ $this->dayINT = intval($day);
+ $this->hourINT = intval($hour);
+ $this->minuteINT = intval($minute);
+ $this->secondINT = intval($second);
+
+ // convert this to timestamp
+ $this->timestamp = mktime($hour, $minute, $second, $month, $day, $year);
+ }
+
+ function year($year=false) {
+ if(!$year) $year = $this->yearINT;
+ return new CalendarYear($year, 1, 1, 0, 0, 0);
+ }
+
+ function month($month=false) {
+ if(!$month) $month = $this->monthINT;
+ return new CalendarMonth($this->yearINT, $month, 1, 0, 0, 0);
+ }
+
+ function day($day=false) {
+ if(!$day) $day = $this->dayINT;
+ return new CalendarDay($this->yearINT, $this->monthINT, $day, 0, 0, 0);
+ }
+
+ function hour($hour=false) {
+ if(!$hour) $hour = $this->hourINT;
+ return new CalendarHour($this->yearINT, $this->monthINT, $this->dayINT, $hour, 0, 0);
+ }
+
+ function minute($minute=false) {
+ if(!$minute) $minute = $this->minuteINT;
+ return new CalendarMinute($this->yearINT, $this->monthINT, $this->dayINT, $this->hourINT, $minute, 0);
+ }
+
+ function second($second=false) {
+ if(!$second) $second = $this->secondINT;
+ return new CalendarSecond($this->yearINT, $this->monthINT, $this->dayINT, $this->hourINT, $this->minuteINT, $second);
+ }
+
+ function timestamp() {
+ return $this->timestamp;
+ }
+
+ function __toString() {
+ return date('Y-m-d H:i:s', $this->timestamp);
+ }
+
+ function format($format) {
+ return date($format, $this->timestamp);
+ }
+
+ function iso() {
+ return date(DATE_ISO, $this->timestamp);
+ }
+
+ function cookie() {
+ return date(DATE_COOKIE, $this->timestamp);
+ }
+
+ function rss() {
+ return date(DATE_RSS, $this->timestamp);
+ }
+
+ function atom() {
+ return date(DATE_ATOM, $this->timestamp);
+ }
+
+ function mysql() {
+ return date('Y-m-d H:i:s', $this->timestamp);
+ }
+
+ function time() {
+ return strftime('%T', $this->timestamp);
+ }
+
+ function ampm() {
+ return strftime('%p', $this->timestamp);
+ }
+
+ function modify($string) {
+ $ts = (is_int($string)) ? $this->timestamp+$string : strtotime($string, $this->timestamp);
+
+ list($year, $month, $day, $hour, $minute, $second) = explode('-', date('Y-m-d-H-i-s', $ts));
+ return new CalendarDay($year, $month, $day, $hour, $minute, $second);
+ }
+
+ function plus($string) {
+ $modifier = (is_int($string)) ? $string : '+' . $string;
+ return $this->modify($modifier);
+ }
+
+ function add($string) {
+ return $this->plus($string);
+ }
+
+ function minus($string) {
+ $modifier = (is_int($string)) ? -$string : '-' . $string;
+ return $this->modify($modifier);
+ }
+
+ function sub($string) {
+ return $this->minus($string);
+ }
+
+ function dmy() {
+ return $this->format('d.m.Y');
+ }
+
+ function padded() {
+ return str_pad($this->int(),2,'0',STR_PAD_LEFT);
+ }
+
+}
+
+class Calendar {
+
+ static $now = 0;
+
+ function __construct() {
+ Calendar::$now = time();
+ }
+
+ function years($start, $end) {
+ $array = array();
+ foreach(range($start, $end) as $year) {
+ $array[] = $this->year($year);
+ }
+ return new CalendarIterator($array);
+ }
+
+ function year($year) {
+ return new CalendarYear($year, 1, 1, 0, 0, 0);
+ }
+
+ function months($year=false) {
+ $year = new CalendarYear($year, 1, 1, 0, 0, 0);
+ return $year->months();
+ }
+
+ function month($year, $month) {
+ return new CalendarMonth($year, $month, 1, 0, 0);
+ }
+
+ function week($year=false, $week=false) {
+ return new CalendarWeek($year, $week);
+ }
+
+ function days($year=false) {
+ $year = new CalendarYear($year);
+ return $year->days();
+ }
+
+ function day($year=false, $month=false, $day=false) {
+ return new CalendarDay($year, $month, $day);
+ }
+
+ function date() {
+
+ $args = func_get_args();
+
+ if(count($args) > 1) {
+
+ $year = isset($args[0]) ? $args[0] : false;
+ $month = isset($args[1]) ? $args[1] : 1;
+ $day = isset($args[2]) ? $args[2] : 1;
+ $hour = isset($args[3]) ? $args[3] : 0;
+ $minute = isset($args[4]) ? $args[4] : 0;
+ $second = isset($args[5]) ? $args[5] : 0;
+
+ } else {
+
+ if(isset($args[0])) {
+ $ts = (is_int($args[0])) ? $args[0] : strtotime($args[0]);
+ } else {
+ $ts = time();
+ }
+
+ if(!$ts) return false;
+
+ list($year, $month, $day, $hour, $minute, $second) = explode('-', date('Y-m-d-H-i-s', $ts));
+
+ }
+
+ return new CalendarDay($year, $month, $day, $hour, $minute, $second);
+
+ }
+
+ function today() {
+ return $this->date('today');
+ }
+
+ function now() {
+ return $this->today();
+ }
+
+ function tomorrow() {
+ return $this->date('tomorrow');
+ }
+
+ function yesterday() {
+ return $this->date('yesterday');
+ }
+
+}
+
+class CalendarYear extends CalendarObj {
+
+ function __toString() {
+ return $this->format('Y');
+ }
+
+ function int() {
+ return $this->yearINT;
+ }
+
+ function months() {
+ $array = array();
+ foreach(range(1, 12) as $month) {
+ $array[] = $this->month($month);
+ }
+ return new CalendarIterator($array);
+ }
+
+ function month($month=1) {
+ return new CalendarMonth($this->yearINT, $month);
+ }
+
+ function weeks() {
+ $array = array();
+ $weeks = (int)date('W', mktime(0,0,0,12,31,$this->int))+1;
+ foreach(range(1,$weeks) as $week) {
+ $array[] = new CalendarWeek($this, $week);
+ }
+ return new CalendarIterator($array);
+ }
+
+ function week($week=1) {
+ return new CalendarWeek($this, $week);
+ }
+
+ function countDays() {
+ return (int)date('z', mktime(0,0,0,12,31,$this->yearINT))+1;
+ }
+
+ function days() {
+
+ $days = $this->countDays();
+ $array = array();
+ $ts = false;
+
+ for($x=0; $x<$days; $x++) {
+ $ts = (!$ts) ? $this->timestamp : strtotime('tomorrow', $ts);
+ $month = date('m', $ts);
+ $day = date('d', $ts);
+ $array[] = $this->month($month)->day($day);
+ }
+
+ return new CalendarIterator($array);
+
+ }
+
+ function next() {
+ return $this->plus('1year')->year();
+ }
+
+ function prev() {
+ return $this->minus('1year')->year();
+ }
+
+ function name() {
+ return $this->int();
+ }
+
+ function firstMonday() {
+ $cal = new Calendar();
+ return $cal->date(strtotime('first monday of ' . date('Y', $this->timestamp)));
+ }
+
+ function firstSunday() {
+ $cal = new Calendar();
+ return $cal->date(strtotime('first sunday of ' . date('Y', $this->timestamp)));
+ }
+
+}
+
+class CalendarMonth extends CalendarObj {
+
+ function __toString() {
+ return $this->format('Y-m');
+ }
+
+ function int() {
+ return $this->monthINT;
+ }
+
+ function weeks($force=false) {
+
+ $first = $this->firstDay();
+ $week = $first->week();
+
+ $currentMonth = $this->int();
+ $nextMonth = $this->next()->int();
+
+ $max = ($force) ? $force : 6;
+
+ for($x=0; $x<$max; $x++) {
+
+ // make sure not to add weeks without a single day in the same month
+ if(!$force && $x>0 && $week->firstDay()->month()->int() != $currentMonth) break;
+
+ $array[] = $week;
+
+ // make sure not to add weeks without a single day in the same month
+ if(!$force && $week->lastDay()->month()->int() != $currentMonth) break;
+
+ $week = $week->next();
+
+ }
+
+ return new CalendarIterator($array);
+
+ }
+
+ function countDays() {
+ return date('t', $this->timestamp);
+ }
+
+ function firstDay() {
+ return new CalendarDay($this->yearINT, $this->monthINT, 1);
+ }
+
+ function lastDay() {
+ return new CalendarDay($this->yearINT, $this->monthINT, $this->countDays());
+ }
+
+ function days() {
+
+ // number of days per month
+ $days = date('t', $this->timestamp);
+ $array = array();
+ $ts = $this->firstDay()->timestamp();
+
+ foreach(range(1, $days) as $day) {
+ $array[] = $this->day($day);
+ }
+
+ return new CalendarIterator($array);
+
+ }
+
+ function day($day=1) {
+ return new CalendarDay($this->yearINT, $this->monthINT, $day);
+ }
+
+ function next() {
+ return $this->plus('1month')->month();
+ }
+
+ function prev() {
+ return $this->minus('1month')->month();
+ }
+
+ function name() {
+ return strftime('%B', $this->timestamp);
+ }
+
+ function shortname() {
+ return strftime('%b', $this->timestamp);
+ }
+
+}
+
+class CalendarWeek extends CalendarObj {
+
+ function __toString() {
+ return $this->firstDay()->format('Y-m-d') . ' - ' . $this->lastDay()->format('Y-m-d');
+ }
+
+ var $weekINT;
+
+ function int() {
+ return $this->weekINT;
+ }
+
+ function __construct($year=false, $week=false) {
+
+ if(!$year) $year = date('Y');
+ if(!$week) $week = date('W');
+
+ $this->yearINT = intval($year);
+ $this->weekINT = intval($week);
+
+ $ts = strtotime('Thursday', strtotime($year . 'W' . $this->padded()));
+ $monday = strtotime('-3days', $ts);
+
+ parent::__construct(date('Y', $monday), date('m', $monday), date('d', $monday), 0, 0, 0);
+
+ }
+
+ function years() {
+ $array = array();
+ $array[] = $this->firstDay()->year();
+ $array[] = $this->lastDay()->year();
+
+ // remove duplicates
+ $array = array_unique($array);
+
+ return new CalendarIterator($array);
+ }
+
+ function months() {
+ $array = array();
+ $array[] = $this->firstDay()->month();
+ $array[] = $this->lastDay()->month();
+
+ // remove duplicates
+ $array = array_unique($array);
+
+ return new CalendarIterator($array);
+ }
+
+ function firstDay() {
+ $cal = new Calendar();
+ return $cal->date($this->timestamp);
+ }
+
+ function lastDay() {
+ $first = $this->firstDay();
+ return $first->plus('6 days');
+ }
+
+ function days() {
+
+ $day = $this->firstDay();
+ $array = array();
+
+ for($x=0; $x<7; $x++) {
+ $array[] = $day;
+ $day = $day->next();
+ }
+
+ return new CalendarIterator($array);
+
+ }
+
+ function next() {
+
+ $next = strtotime('Thursday next week', $this->timestamp);
+ $year = date('Y', $next);
+ $week = date('W', $next);
+
+ return new CalendarWeek($year, $week);
+
+ }
+
+ function prev() {
+
+ $prev = strtotime('Monday last week', $this->timestamp);
+ $year = date('Y', $prev);
+ $week = date('W', $prev);
+
+ return new CalendarWeek($year, $week);
+
+ }
+
+}
+
+
+class CalendarDay extends CalendarObj {
+
+ function __toString() {
+ return $this->format('Y-m-d');
+ }
+
+ function int() {
+ return $this->dayINT;
+ }
+
+ function week() {
+ $week = date('W', $this->timestamp);
+ $year = ($this->monthINT == 1 && $week > 5) ? $this->year()->prev() : $this->year();
+ return new CalendarWeek($year->int(), $week);
+ }
+
+ function next() {
+ return $this->plus('1day');
+ }
+
+ function prev() {
+ return $this->minus('1day');
+ }
+
+ function weekday() {
+ return date('N', $this->timestamp);
+ }
+
+ function name() {
+ return strftime('%A', $this->timestamp);
+ }
+
+ function shortname() {
+ return strftime('%a', $this->timestamp);
+ }
+
+ function isToday() {
+ $cal = new Calendar();
+ return $this == $cal->today();
+ }
+
+ function isYesterday() {
+ $cal = new Calendar();
+ return $this == $cal->yesterday();
+ }
+
+ function isTomorrow() {
+ $cal = new Calendar();
+ return $this == $cal->tomorrow();
+ }
+
+ function isInThePast() {
+ return ($this->timestamp < Calendar::$now) ? true : false;
+ }
+
+ function isInTheFuture() {
+ return ($this->timestamp > Calendar::$now) ? true : false;
+ }
+
+ function isWeekend() {
+ $num = $this->format('w');
+ return ($num == 6 || $num == 0) ? true : false;
+ }
+
+ function hours() {
+
+ $obj = $this;
+ $array = array();
+
+ while($obj->int() == $this->int()) {
+ $array[] = $obj->hour();
+ $obj = $obj->plus('1hour');
+ }
+
+ return new CalendarIterator($array);
+
+ }
+
+}
+
+class CalendarHour extends CalendarObj {
+
+ function int() {
+ return $this->hourINT;
+ }
+
+ function minutes() {
+
+ $obj = $this;
+ $array = array();
+
+ while($obj->hourINT == $this->hourINT) {
+ $array[] = $obj;
+ $obj = $obj->plus('1minute')->minute();
+ }
+
+ return new CalendarIterator($array);
+
+ }
+
+ function next() {
+ return $this->plus('1hour')->hour();
+ }
+
+ function prev() {
+ return $this->minus('1hour')->hour();
+ }
+
+}
+
+class CalendarMinute extends CalendarObj {
+
+ function int() {
+ return $this->minuteINT;
+ }
+
+ function seconds() {
+
+ $obj = $this;
+ $array = array();
+
+ while($obj->minuteINT == $this->minuteINT) {
+ $array[] = $obj;
+ $obj = $obj->plus('1second')->second();
+ }
+
+ return new CalendarIterator($array);
+
+ }
+
+ function next() {
+ return $this->plus('1minute')->minute();
+ }
+
+ function prev() {
+ return $this->minus('1minute')->minute();
+ }
+
+}
+
+class CalendarSecond extends CalendarObj {
+
+ function int() {
+ return $this->secondINT;
+ }
+
+ function next() {
+ return $this->plus('1second')->second();
+ }
+
+ function prev() {
+ return $this->minus('1second')->second();
+ }
+
+}
+
+
+
185 lib/gantti.php
@@ -0,0 +1,185 @@
+<?php
+
+require('calendar.php');
+
+class Gantti {
+
+ var $cal = null;
+ var $data = array();
+ var $first = false;
+ var $last = false;
+ var $options = array();
+ var $cellstyle = false;
+ var $blocks = array();
+ var $months = array();
+ var $days = array();
+ var $seconds = 0;
+
+ function __construct($data, $params=array()) {
+
+ $defaults = array(
+ 'title' => false,
+ 'cellwidth' => 40,
+ 'cellheight' => 40,
+ 'today' => true,
+ );
+
+ $this->options = array_merge($defaults, $params);
+ $this->cal = new Calendar();
+ $this->data = $data;
+ $this->seconds = 60*60*24;
+
+ $this->cellstyle = 'style="width: ' . $this->options['cellwidth'] . 'px; height: ' . $this->options['cellheight'] . 'px"';
+
+ // parse data and find first and last date
+ $this->parse();
+
+ }
+
+ function parse() {
+
+ foreach($this->data as $d) {
+
+ $this->blocks[] = array(
+ 'label' => $d['label'],
+ 'start' => $start = strtotime($d['start']),
+ 'end' => $end = strtotime($d['end']),
+ 'class' => @$d['class']
+ );
+
+ if(!$this->first || $this->first > $start) $this->first = $start;
+ if(!$this->last || $this->last < $end) $this->last = $end;
+
+ }
+
+ $this->first = $this->cal->date($this->first);
+ $this->last = $this->cal->date($this->last);
+
+ $current = $this->first->month();
+ $lastDay = $this->last->month()->lastDay()->timestamp;
+
+ // build the months
+ while($current->lastDay()->timestamp <= $lastDay) {
+ $month = $current->month();
+ $this->months[] = $month;
+ foreach($month->days() as $day) {
+ $this->days[] = $day;
+ }
+ $current = $current->next();
+ }
+
+ }
+
+ function render() {
+
+ $html = array();
+
+ // common styles
+ $cellstyle = 'style="line-height: ' . $this->options['cellheight'] . 'px; height: ' . $this->options['cellheight'] . 'px"';
+ $wrapstyle = 'style="width: ' . $this->options['cellwidth'] . 'px"';
+ $totalstyle = 'style="width: ' . (count($this->days)*$this->options['cellwidth']) . 'px"';
+ // start the diagram
+ $html[] = '<figure class="gantt">';
+
+ // set a title if available
+ if($this->options['title']) {
+ $html[] = '<figcaption>' . $this->options['title'] . '</figcaption>';
+ }
+
+ // sidebar with labels
+ $html[] = '<aside>';
+ $html[] = '<ul class="gantt-labels" style="margin-top: ' . (($this->options['cellheight']*2)+1) . 'px">';
+ foreach($this->blocks as $i => $block) {
+ $html[] = '<li class="gantt-label"><strong ' . $cellstyle . '>' . $block['label'] . '</strong></li>';
+ }
+ $html[] = '</ul>';
+ $html[] = '</aside>';
+
+ // data section
+ $html[] = '<section class="gantt-data">';
+
+ // data header section
+ $html[] = '<header>';
+
+ // months headers
+ $html[] = '<ul class="gantt-months" ' . $totalstyle . '>';
+ foreach($this->months as $month) {
+ $html[] = '<li class="gantt-month" style="width: ' . ($this->options['cellwidth'] * $month->countDays()) . 'px"><strong ' . $cellstyle . '>' . $month->name() . '</strong></li>';
+ }
+ $html[] = '</ul>';
+
+ // days headers
+ $html[] = '<ul class="gantt-days" ' . $totalstyle . '>';
+ foreach($this->days as $day) {
+
+ $weekend = ($day->isWeekend()) ? ' weekend' : '';
+ $today = ($day->isToday()) ? ' today' : '';
+
+ $html[] = '<li class="gantt-day' . $weekend . $today . '" ' . $wrapstyle . '><span ' . $cellstyle . '>' . $day->padded() . '</span></li>';
+ }
+ $html[] = '</ul>';
+
+ // end header
+ $html[] = '</header>';
+
+ // main items
+ $html[] = '<ul class="gantt-items" ' . $totalstyle . '>';
+
+ foreach($this->blocks as $i => $block) {
+
+ $html[] = '<li class="gantt-item">';
+
+ // days
+ $html[] = '<ul class="gantt-days">';
+ foreach($this->days as $day) {
+
+ $weekend = ($day->isWeekend()) ? ' weekend' : '';
+ $today = ($day->isToday()) ? ' today' : '';
+
+ $html[] = '<li class="gantt-day' . $weekend . $today . '" ' . $wrapstyle . '><span ' . $cellstyle . '>' . $day . '</span></li>';
+ }
+ $html[] = '</ul>';
+
+ // the block
+ $days = (($block['end'] - $block['start']) / $this->seconds);
+ $offset = (($block['start'] - $this->first->month()->timestamp) / $this->seconds);
+ $top = round($i * ($this->options['cellheight'] + 1));
+ $left = round($offset * $this->options['cellwidth']);
+ $width = round($days * $this->options['cellwidth'] - 9);
+ $height = round($this->options['cellheight']-8);
+ $class = ($block['class']) ? ' ' . $block['class'] : '';
+ $html[] = '<span class="gantt-block' . $class . '" style="left: ' . $left . 'px; width: ' . $width . 'px; height: ' . $height . 'px"><strong class="gantt-block-label">' . $days . '</strong></span>';
+ $html[] = '</li>';
+
+ }
+
+ $html[] = '</ul>';
+
+ if($this->options['today']) {
+
+ // today
+ $today = $this->cal->today();
+ $offset = (($today->timestamp - $this->first->month()->timestamp) / $this->seconds);
+ $left = round($offset * $this->options['cellwidth']) + round(($this->options['cellwidth'] / 2) - 1);
+
+ if($today->timestamp > $this->first->timestamp && $today->timestamp < $this->last->timestamp) {
+ $html[] = '<time style="top: ' . ($this->options['cellheight'] * 2) . 'px; left: ' . $left . 'px" datetime="' . $today->format('Y-m-d') . '">Today</time>';
+ }
+
+ }
+
+ // end data section
+ $html[] = '</section>';
+
+ // end diagram
+ $html[] = '</figure>';
+
+ return implode('', $html);
+
+ }
+
+ function __toString() {
+ return $this->render();
+ }
+
+}
173 styles/css/gantti.css
@@ -0,0 +1,173 @@
+/* Sass Variables */
+/* gantt styles */
+.gantt {
+ position: relative;
+ overflow: hidden;
+ color: #93a1a1;
+ background: #002b36; }
+
+.gantt * {
+ font-weight: normal;
+ margin: 0;
+ padding: 0; }
+
+.gantt li {
+ list-style: none; }
+
+/* optional title */
+.gantt figcaption {
+ position: absolute;
+ top: 25px;
+ left: 20px;
+ font-size: 20px;
+ color: white;
+ text-transform: uppercase;
+ letter-spacing: 4px; }
+
+/* sidebar */
+.gantt aside {
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ top: 0;
+ width: 199px;
+ border-right: 1px solid #00171c;
+ z-index: 2; }
+
+.gantt aside:before {
+ position: absolute;
+ right: -7px;
+ pointer-events: none;
+ width: 7px;
+ top: 0;
+ bottom: 0;
+ content: "";
+ border-left: 1px solid rgba(255, 255, 255, 0.03);
+ background: -webkit-linear-gradient(left, rgba(0, 43, 54, 0.7), rgba(0, 43, 54, 0));
+ background: -moz-linear-gradient(left, rgba(0, 43, 54, 0.7), rgba(0, 43, 54, 0));
+ background: linear-gradient(left, rgba(0, 43, 54, 0.7), rgba(0, 43, 54, 0));
+ z-index: 3; }
+
+.gantt aside .gantt-labels {
+ border-top: 1px solid #001f27; }
+
+.gantt aside .gantt-label strong {
+ display: block;
+ padding: 0 20px;
+ color: #93a1a1;
+ border-bottom: 1px solid #001f27; }
+
+/* data section */
+.gantt-data {
+ position: relative;
+ overflow-x: scroll;
+ margin-left: 200px;
+ white-space: nowrap; }
+
+/* data section header */
+.gantt header .gantt-months {
+ overflow: hidden; }
+
+.gantt header .gantt-month {
+ float: left;
+ text-align: center; }
+
+.gantt header .gantt-month strong {
+ display: block;
+ border-right: 1px solid #001f27;
+ border-bottom: 1px solid #001f27; }
+
+.gantt header .gantt-day span {
+ text-indent: 0;
+ text-align: center; }
+
+.gantt header .gantt-day.today span {
+ color: white; }
+
+/* data items */
+.gantt-item {
+ position: relative; }
+
+.gantt-days {
+ overflow: hidden; }
+
+.gantt-day {
+ float: left; }
+
+.gantt-day span {
+ display: block;
+ border-right: 1px solid #001f27;
+ border-bottom: 1px solid #001f27;
+ text-indent: -6000px; }
+
+.gantt-day.weekend span {
+ background: #073642; }
+
+/* data blocks */
+.gantt-block {
+ position: absolute;
+ top: 0;
+ z-index: 1;
+ margin: 4px;
+ border-radius: 3px;
+ -webkit-box-shadow: rgba(0, 0, 0, 0.9) 0 2px 6px, rgba(255, 255, 255, 0.2) 0 1px 0 inset;
+ -moz-box-shadow: rgba(0, 0, 0, 0.9) 0 2px 6px, rgba(255, 255, 255, 0.2) 0 1px 0 inset;
+ box-shadow: rgba(0, 0, 0, 0.9) 0 2px 6px, rgba(255, 255, 255, 0.2) 0 1px 0 inset;
+ opacity: .9; }
+
+.gantt-block-label {
+ display: block;
+ color: white;
+ padding: 5px 10px; }
+
+/* block colors */
+.gantt-block {
+ background: #268bd2; }
+
+.gantt-block.important {
+ background: #b58900; }
+
+.gantt-block.urgent {
+ background: #d33682; }
+
+/* today sign */
+.gantt time {
+ position: absolute;
+ top: 0;
+ width: 2px;
+ background: white;
+ bottom: 0;
+ z-index: 1000;
+ text-indent: -6000px;
+ -webkit-box-shadow: rgba(0, 0, 0, 0.3) 0 0 10px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.3) 0 0 10px;
+ box-shadow: rgba(0, 0, 0, 0.3) 0 0 10px; }
+
+.gantt time:before {
+ position: absolute;
+ content: "";
+ top: 0;
+ left: -4px;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-top: 5px solid white; }
+
+/* scrollbar styles */
+.gantt ::-webkit-scrollbar {
+ background: #002b36;
+ height: 10px; }
+
+.gantt ::-webkit-scrollbar-thumb {
+ background: #93a1a1;
+ -webkit-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0 inset;
+ -moz-box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0 inset;
+ box-shadow: rgba(255, 255, 255, 0.1) 0 1px 0 inset; }
+
+/* selection styles */
+.gantt ::-moz-selection {
+ background: #fff;
+ color: #000; }
+
+.gantt ::selection {
+ background: #fff;
+ color: #000; }
70 styles/css/screen.css
@@ -0,0 +1,70 @@
+@import url(http://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700);
+article, aside, details, figcaption, figure, footer, header, hgroup, nav, section {
+ display: block; }
+
+* {
+ margin: 0;
+ padding: 0; }
+
+body {
+ font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ line-height: 22px;
+ background: #fdf6e3;
+ color: #657b83;
+ padding: 50px 0; }
+
+a {
+ color: #d33682;
+ text-decoration: none;
+ border-bottom: 1px solid rgba(0, 0, 0, 0.1); }
+
+header, article {
+ width: 500px;
+ margin: 0 auto;
+ padding: 50px 20px; }
+
+figure {
+ font-size: 12px;
+ line-height: 18px; }
+
+h1 {
+ font-size: 30px;
+ margin-bottom: 10px;
+ text-transform: uppercase;
+ color: #d33682; }
+
+h2 {
+ color: #b58900;
+ font-weight: normal;
+ margin-bottom: 10px; }
+
+p {
+ margin-bottom: 20px; }
+
+ul li {
+ list-style: square; }
+
+article {
+ padding-bottom: 100px; }
+
+pre {
+ font-family: "Monaco", "Courier", monospace;
+ position: relative;
+ overflow: auto;
+ background: #002b36;
+ color: #93a1a1;
+ box-shadow: rgba(0, 0, 0, 0.8) 0px 2px 10px inset;
+ padding: 20px;
+ font-size: 14px;
+ line-height: 24px;
+ margin-bottom: 24px;
+ border-radius: 3px; }
+
+pre code {
+ font-family: "Monaco", "Courier", monospace;
+ background: none;
+ padding: 0;
+ white-space: pre;
+ box-shadow: none;
+ border-radius: 0; }
206 styles/scss/gantti.scss
@@ -0,0 +1,206 @@
+/* Sass Variables */
+
+$color-background-dark: #002b36;
+$color-background-light: #073642;
+
+$color-lines: darken($color-background-dark, 3%);
+$color-today: #fff;
+
+$color-text: #93a1a1;
+$color-text-today: #fff;
+$color-text-label-aside: $color-text;
+$color-text-label-block: #fff;
+$color-text-title: #fff;
+
+$color-block-default: #268bd2;
+$color-block-important: #b58900;
+$color-block-urgent: #d33682;
+
+$color-scrollbar-back: $color-background-dark;
+$color-scrollbar-thumb: #93a1a1;
+
+$aside-width: 200px;
+
+/* gantt styles */
+.gantt {
+ position: relative;
+ overflow: hidden;
+ color: $color-text;
+ background: $color-background-dark;
+}
+.gantt * {
+ font-weight: normal;
+ margin: 0;
+ padding: 0;
+}
+.gantt li {
+ list-style: none;
+}
+
+/* optional title */
+.gantt figcaption {
+ position: absolute;
+ top: 25px;
+ left: 20px;
+ font-size: 20px;
+ color: $color-text-title;
+ text-transform: uppercase;
+ letter-spacing: 4px;
+}
+
+/* sidebar */
+.gantt aside {
+ position: absolute;
+ left: 0;
+ bottom: 0;
+ top: 0;
+ width: $aside-width - 1;
+ border-right: 1px solid darken($color-lines, 2%);
+ z-index: 2;
+}
+.gantt aside:before {
+ position: absolute;
+ right: -7px;
+ pointer-events: none;
+ width: 7px;
+ top: 0;
+ bottom: 0;
+ content: "";
+ border-left: 1px solid rgba(255,255,255, .03);
+ background: -webkit-linear-gradient(left, rgba($color-background-dark,.7), rgba($color-background-dark,0));
+ background: -moz-linear-gradient(left, rgba($color-background-dark,.7), rgba($color-background-dark,0));
+ background: linear-gradient(left, rgba($color-background-dark,.7), rgba($color-background-dark,0));
+ z-index: 3;
+}
+.gantt aside .gantt-labels {
+ border-top: 1px solid $color-lines;
+}
+.gantt aside .gantt-label strong {
+ display: block;
+ padding: 0 20px;
+ color: $color-text-label-aside;
+ border-bottom: 1px solid $color-lines;
+}
+
+/* data section */
+.gantt-data {
+ position: relative;
+ overflow-x: scroll;
+ margin-left: $aside-width;
+ white-space: nowrap;
+}
+
+/* data section header */
+.gantt header .gantt-months {
+ overflow: hidden;
+}
+.gantt header .gantt-month {
+ float: left;
+ text-align: center;
+}
+.gantt header .gantt-month strong {
+ display: block;
+ border-right: 1px solid $color-lines;
+ border-bottom: 1px solid $color-lines;
+}
+.gantt header .gantt-day span {
+ text-indent: 0;
+ text-align: center;
+}
+.gantt header .gantt-day.today span {
+ color: $color-text-today;
+}
+
+/* data items */
+.gantt-item {
+ position: relative;
+}
+.gantt-days {
+ overflow: hidden;
+}
+.gantt-day {
+ float: left;
+}
+.gantt-day span {
+ display: block;
+ border-right: 1px solid $color-lines;
+ border-bottom: 1px solid $color-lines;
+ text-indent: -6000px;
+}
+.gantt-day.weekend span {
+ background: $color-background-light;
+}
+
+/* data blocks */
+.gantt-block {
+ position: absolute;
+ top: 0;
+ z-index: 1;
+ margin: 4px;
+ border-radius: 3px;
+ -webkit-box-shadow: rgba(0,0,0, .9) 0 2px 6px, rgba(255,255,255, .2) 0 1px 0 inset;
+ -moz-box-shadow: rgba(0,0,0, .9) 0 2px 6px, rgba(255,255,255, .2) 0 1px 0 inset;
+ box-shadow: rgba(0,0,0, .9) 0 2px 6px, rgba(255,255,255, .2) 0 1px 0 inset;
+ opacity: .9;
+}
+.gantt-block-label {
+ display: block;
+ color: $color-text-label-block;
+ padding: 5px 10px;
+}
+
+/* block colors */
+.gantt-block {
+ background: $color-block-default;
+}
+.gantt-block.important {
+ background: $color-block-important;
+}
+.gantt-block.urgent {
+ background: $color-block-urgent;
+}
+
+/* today sign */
+.gantt time {
+ position: absolute;
+ top: 0;
+ width: 2px;
+ background: $color-today;
+ bottom: 0;
+ z-index: 1000;
+ text-indent: -6000px;
+ -webkit-box-shadow: rgba(0,0,0, .3) 0 0 10px;
+ -moz-box-shadow: rgba(0,0,0, .3) 0 0 10px;
+ box-shadow: rgba(0,0,0, .3) 0 0 10px;
+}
+.gantt time:before {
+ position: absolute;
+ content: "";
+ top: 0;
+ left: -4px;
+ border-left: 5px solid transparent;
+ border-right: 5px solid transparent;
+ border-top: 5px solid $color-today;
+}
+
+/* scrollbar styles */
+.gantt ::-webkit-scrollbar {
+ background: $color-scrollbar-back;
+ height: 10px;
+}
+.gantt ::-webkit-scrollbar-thumb {
+ background: $color-scrollbar-thumb;
+ -webkit-box-shadow: rgba(255,255,255, .1) 0 1px 0 inset;
+ -moz-box-shadow: rgba(255,255,255, .1) 0 1px 0 inset;
+ box-shadow: rgba(255,255,255, .1) 0 1px 0 inset;
+}
+
+/* selection styles */
+.gantt ::-moz-selection {
+ background: #fff;
+ color: #000;
+}
+.gantt ::selection {
+ background: #fff;
+ color: #000;
+}
84 styles/scss/screen.scss
@@ -0,0 +1,84 @@
+@import url(http://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700);
+
+article, aside, details, figcaption, figure, footer, header, hgroup, nav, section {
+ display: block;
+}
+
+* {
+ margin: 0;
+ padding: 0;
+}
+
+body {
+ font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-size: 14px;
+ line-height: 22px;
+ background: #fdf6e3;
+ color: #657b83;
+ padding: 50px 0;
+}
+
+a {
+ color: #d33682;
+ text-decoration: none;
+ border-bottom: 1px solid rgba(0,0,0, .1);
+}
+
+header, article {
+ width: 500px;
+ margin: 0 auto;
+ padding: 50px 20px;
+}
+
+figure {
+ font-size: 12px;
+ line-height: 18px;
+}
+
+h1 {
+ font-size: 30px;
+ margin-bottom: 10px;
+ text-transform: uppercase;
+ color: #d33682;
+}
+
+h2 {
+ color: #b58900;
+ font-weight: normal;
+ margin-bottom: 10px;
+}
+
+p {
+ margin-bottom: 20px;
+}
+
+ul li {
+ list-style: square;
+}
+
+article {
+ padding-bottom: 100px;
+}
+
+pre {
+ font-family: "Monaco", "Courier", monospace;
+ position: relative;
+ overflow: auto;
+ background: #002b36;
+ color: #93a1a1;
+ box-shadow: rgba(0,0,0, .8) 0px 2px 10px inset;
+ padding: 20px;
+ font-size: 14px;
+ line-height: 24px;
+ margin-bottom: 24px;
+ border-radius: 3px;
+}
+
+pre code {
+ font-family: "Monaco", "Courier", monospace;
+ background: none;
+ padding: 0;
+ white-space: pre;
+ box-shadow: none;
+ border-radius: 0;
+}

0 comments on commit 9196f81

Please sign in to comment.