TimelineHelper.php 5.7 KB

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