TimelineHelper.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <?php
  2. App::uses('AppHelper', 'View/Helper');
  3. /**
  4. * TimelineHelper for easy output of a timeline with multiple items.
  5. *
  6. * You need to include your css and js file, manually:
  7. *
  8. * echo $this->Html->script('timeline/timeline');
  9. * echo $this->Html->css('/js/timeline/timeline');
  10. *
  11. * @link http://almende.github.io/chap-links-library/timeline.html
  12. * @author Mark Scherer
  13. * @license http://opensource.org/licenses/mit-license.php MIT
  14. */
  15. class TimelineHelper extends AppHelper {
  16. public $helpers = ['Js'];
  17. protected $_defaultConfig = [
  18. 'id' => 'mytimeline',
  19. 'selectable' => false,
  20. 'editable' => false,
  21. 'min' => null, // Min date.
  22. 'max' => null, // Max date.
  23. 'width' => '100%',
  24. 'height' => null, // Auto.
  25. 'style' => 'box',
  26. 'current' => null, // Current time.
  27. ];
  28. protected $_items = [];
  29. /**
  30. * Constructor
  31. *
  32. * @param View $View The View this helper is being attached to.
  33. * @param array $settings Configuration settings for the helper.
  34. */
  35. public function __construct(View $View, $settings = []) {
  36. $this->settings = $this->_defaultConfig;
  37. parent::__construct($View, $settings);
  38. }
  39. /**
  40. * Apply settings and merge them with the defaults.
  41. *
  42. * Possible values are (with their default values):
  43. * - 'min',
  44. * - 'max',
  45. * - 'width'
  46. * - 'height'
  47. * - 'minHeight'
  48. * - 'selectable' => false,
  49. * - 'editable' => false,
  50. * - 'moveable' => true
  51. * - 'animate' => true,
  52. * - 'animateZoom' => true,
  53. * - 'axisOnTop' => false,
  54. * - 'cluster' => false
  55. * - 'locale' (string)
  56. * - 'style' (string)
  57. * - ...
  58. *
  59. * @link http://almende.github.io/chap-links-library/js/timeline/doc/
  60. * @param array $settings Key value pairs to merge with current settings.
  61. * @return void
  62. */
  63. public function settings($settings) {
  64. $this->settings = Hash::merge($this->settings, $settings);
  65. }
  66. /**
  67. * Add timeline item.
  68. *
  69. * Requires at least:
  70. * - start (date or datetime)
  71. * - content (string)
  72. * Further data options:
  73. * - end (date or datetime)
  74. * - group (string)
  75. * - className (string)
  76. * - editable (boolean)
  77. *
  78. * @link http://almende.github.io/chap-links-library/js/timeline/doc/
  79. * @param array
  80. * @return void
  81. */
  82. public function addItem($item) {
  83. $this->_items[] = $item;
  84. }
  85. /**
  86. * Add timeline items as an array of items.
  87. *
  88. * @see TimelineHelper::addItem()
  89. * @return void
  90. */
  91. public function addItems($items) {
  92. foreach ($items as $item) {
  93. $this->_items[] = $item;
  94. }
  95. }
  96. /**
  97. * Finalize the timeline and write the javascript to the buffer.
  98. * Make sure that your view does also output the buffer at some place!
  99. *
  100. * @param bool $return If the output should be returned instead
  101. * @return void or string Javascript if $return is true
  102. */
  103. public function finalize($return = false) {
  104. $settings = $this->settings;
  105. $timelineId = $settings['id'];
  106. $data = $this->_format($this->_items);
  107. $current = '';
  108. if ($settings['current']) {
  109. $dateString = date('Y-m-d H:i:s', time());
  110. $current = 'timeline.setCurrentTime(' . $this->_date($dateString) . ');';
  111. }
  112. unset($settings['id']);
  113. unset($settings['current']);
  114. $options = $this->_options($settings);
  115. $script = <<<JS
  116. var timeline;
  117. var data;
  118. var options;
  119. // Called when the Visualization API is loaded.
  120. function drawVisualization() {
  121. // Create a JSON data table
  122. data = $data
  123. options = $options
  124. // Instantiate our timeline object.
  125. timeline = new links.Timeline(document.getElementById('$timelineId'));
  126. // Draw our timeline with the created data and options
  127. timeline.draw(data, options);
  128. $current
  129. }
  130. drawVisualization();
  131. JS;
  132. if ($return) {
  133. return $script;
  134. }
  135. $this->Js->buffer($script);
  136. }
  137. /**
  138. * Format options to JS code
  139. *
  140. * @param array $options
  141. * @return string
  142. */
  143. protected function _options($options) {
  144. $e = [];
  145. foreach ($options as $option => $value) {
  146. if ($value === null) {
  147. continue;
  148. }
  149. if (is_string($value)) {
  150. $value = '\'' . $value . '\'';
  151. } elseif (is_object($value)) { // Datetime?
  152. $value = $this->_date($value);
  153. } elseif (is_bool($value)) {
  154. $value = $value ? 'true' : 'false';
  155. } else {
  156. $value = str_replace('\'', '\\\'', $value);
  157. }
  158. $e[] = '\'' . $option . '\': ' . $value;
  159. }
  160. $string = '{' . PHP_EOL . "\t" . implode(',' . PHP_EOL . "\t", $e) . PHP_EOL . '}';
  161. return $string;
  162. }
  163. /**
  164. * Format items to JS code
  165. *
  166. * @see TimelineHelper::addItem()
  167. * @param array $items
  168. * @return string
  169. */
  170. protected function _format($items) {
  171. $e = [];
  172. foreach ($items as $item) {
  173. $tmp = [];
  174. foreach ($item as $key => $row) {
  175. switch ($key) {
  176. case 'editable':
  177. $tmp[] = $row ? 'true' : 'false';
  178. break;
  179. case 'start':
  180. case 'end':
  181. $tmp[] = '\'' . $key . '\': ' . $this->_date($row);
  182. break;
  183. default:
  184. $tmp[] = '\'' . $key . '\': \'' . str_replace('\'', '\\\'', $row) . '\'';
  185. }
  186. }
  187. $e[] = '{' . implode(',' . PHP_EOL, $tmp) . '}';
  188. }
  189. $string = '[' . implode(',' . PHP_EOL, $e) . '];';
  190. return $string;
  191. }
  192. /**
  193. * Format date to JS code.
  194. *
  195. * @param string|DateTime $date
  196. * @return string
  197. */
  198. protected function _date($date) {
  199. if (is_object($date)) {
  200. // Datetime?
  201. $datePieces = [];
  202. $datePieces[] = $date->format('Y');
  203. // JavaScript uses 0-indexed months, so we need to subtract 1 month from PHP's output
  204. $datePieces[] = (int)($date->format('m') - 1);
  205. $datePieces[] = (int)$date->format('d');
  206. $datePieces[] = (int)$date->format('H');
  207. $datePieces[] = (int)$date->format('i');
  208. $datePieces[] = (int)$date->format('s');
  209. } else {
  210. // As string (fallback).
  211. $dateTime = explode(' ', $date, 2);
  212. $datePieces = [];
  213. $datePieces[] = substr($dateTime[0], 0, 4);
  214. // JavaScript uses 0-indexed months, so we need to subtract 1 month from the output
  215. $datePieces[] = (int)(substr($dateTime[0], 5, 2) - 1);
  216. $datePieces[] = (int)substr($dateTime[0], 8, 2);
  217. if (!empty($dateTime[1])) {
  218. $datePieces[] = (int)substr($dateTime[1], 0, 2);
  219. $datePieces[] = (int)substr($dateTime[1], 3, 2);
  220. $datePieces[] = (int)substr($dateTime[1], 6, 2);
  221. }
  222. }
  223. return 'new Date(' . implode(', ', $datePieces) . ')';
  224. }
  225. }