vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
10 KiB

  1. /**
  2. * Created by Alex on 10/3/2014.
  3. */
  4. var moment = require('../module/moment');
  5. /**
  6. * used in Core to convert the options into a volatile variable
  7. *
  8. * @param Core
  9. */
  10. exports.convertHiddenOptions = function(body, hiddenDates) {
  11. var hiddenTimes = hiddenDates.specific;
  12. if (hiddenTimes) {
  13. if (Array.isArray(hiddenTimes) == true) {
  14. for (var i = 0; i < hiddenTimes.length; i++) {
  15. var dateItem = {};
  16. dateItem.start = moment(hiddenTimes[i].start).toDate().valueOf();
  17. dateItem.end = moment(hiddenTimes[i].end).toDate().valueOf();
  18. body.hiddenDates.push(dateItem);
  19. }
  20. body.hiddenDates.sort(function (a, b) {
  21. return a.start - b.start;
  22. }); // sort by start time
  23. }
  24. else {
  25. body.hiddenDates = [{
  26. start: moment(hiddenTimes.start).toDate().valueOf(),
  27. end: moment(hiddenTimes.end).toDate().valueOf()
  28. }
  29. ];
  30. }
  31. }
  32. };
  33. exports.updateHiddenDates = function (body, hiddenDates) {
  34. if (hiddenDates && hiddenDates.periodic) {
  35. body.hiddenDates = [];
  36. exports.convertHiddenOptions(body, hiddenDates);
  37. var start = moment(body.range.start);
  38. var end = moment(body.range.end);
  39. if (hiddenDates.periodic.days) {
  40. var nextStartDay = moment(body.range.start);
  41. var nextEndDay = moment(body.range.start);
  42. for (var i = 0; i < hiddenDates.periodic.days.length; i++) {
  43. var startDay = hiddenDates.periodic.days[i].start;
  44. var endDay = hiddenDates.periodic.days[i].end;
  45. nextStartDay.isoWeekday(startDay);
  46. nextEndDay.isoWeekday(endDay);
  47. if (start < nextStartDay) {
  48. nextStartDay.isoWeekday(startDay - 7);
  49. }
  50. if (start < nextEndDay) {
  51. nextEndDay.isoWeekday(endDay - 7);
  52. }
  53. nextStartDay.milliseconds(0);
  54. nextStartDay.seconds(0);
  55. nextStartDay.minutes(0);
  56. nextStartDay.hours(0);
  57. nextEndDay.milliseconds(0);
  58. nextEndDay.seconds(0);
  59. nextEndDay.minutes(0);
  60. nextEndDay.hours(0);
  61. while (nextStartDay < end) {
  62. body.hiddenDates.push({start: nextStartDay.valueOf(), end: nextEndDay.valueOf()});
  63. nextStartDay.isoWeekday(startDay + 7);
  64. nextEndDay.isoWeekday(endDay + 7);
  65. }
  66. body.hiddenDates.push({start: nextStartDay.valueOf(), end: nextEndDay.valueOf()});
  67. }
  68. }
  69. if (hiddenDates.periodic.times) {
  70. var nextStartDay = moment(body.range.start);
  71. var nextEndDay = moment(body.range.start);
  72. end = end.valueOf();
  73. for (var i = 0; i < hiddenDates.periodic.times.length; i++) {
  74. var startTime = hiddenDates.periodic.times[i].start.split(":");
  75. var endTime = hiddenDates.periodic.times[i].end.split(":");
  76. nextStartDay.milliseconds(0);
  77. nextStartDay.seconds(startTime[2]);
  78. nextStartDay.minutes(startTime[1]);
  79. nextStartDay.hours(startTime[0]);
  80. nextEndDay.milliseconds(0);
  81. nextEndDay.seconds(endTime[2]);
  82. nextEndDay.minutes(endTime[1]);
  83. nextEndDay.hours(endTime[0]);
  84. nextStartDay = nextStartDay.valueOf();
  85. nextEndDay = nextEndDay.valueOf();
  86. if (endTime[0] < startTime[0]) {
  87. nextEndDay += 3600000*24;
  88. }
  89. nextStartDay -= 7*3600000*24;
  90. nextEndDay -= 7*3600000*24;
  91. while (nextStartDay < (end + 7*3600000*24)) {
  92. body.hiddenDates.push({start: nextStartDay.valueOf(), end: nextEndDay.valueOf()});
  93. nextStartDay += 3600000*24;
  94. nextEndDay += 3600000*24;
  95. }
  96. }
  97. }
  98. exports.removeDuplicates(body);
  99. //var startHidden = exports.isHidden(body.range.start, body.hiddenDates);
  100. //var endHidden = exports.isHidden(body.range.end,body.hiddenDates);
  101. }
  102. }
  103. exports.removeDuplicates = function(body) {
  104. var hiddenDates = body.hiddenDates;
  105. var safeDates = [];
  106. for (var i = 0; i < hiddenDates.length; i++) {
  107. for (var j = 0; j < hiddenDates.length; j++) {
  108. if (i != j && hiddenDates[j].remove != true && hiddenDates[i].remove != true) {
  109. // j inside i
  110. if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) {
  111. hiddenDates[j].remove = true;
  112. }
  113. // j start inside i
  114. else if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].start <= hiddenDates[i].end) {
  115. hiddenDates[i].end = hiddenDates[j].end;
  116. hiddenDates[j].remove = true;
  117. }
  118. // j end inside i
  119. else if (hiddenDates[j].end >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) {
  120. hiddenDates[i].start = hiddenDates[j].start;
  121. hiddenDates[j].remove = true;
  122. }
  123. }
  124. }
  125. }
  126. for (var i = 0; i < hiddenDates.length; i++) {
  127. if (hiddenDates[i].remove !== true) {
  128. safeDates.push(hiddenDates[i]);
  129. }
  130. }
  131. body.hiddenDates = safeDates;
  132. body.hiddenDates.sort(function (a, b) {
  133. return a.start - b.start;
  134. }); // sort by start time
  135. }
  136. exports.printDates = function(dates) {
  137. for (var i =0; i < dates.length; i++) {
  138. console.log(i, new Date(dates[i].start),new Date(dates[i].end), dates[i].start, dates[i].end, dates[i].remove);
  139. }
  140. }
  141. /**
  142. * Used in TimeStep to avoid the hidden times.
  143. * @param timeStep
  144. * @param previousTime
  145. */
  146. exports.stepOverHiddenDates = function(timeStep, previousTime) {
  147. var stepInHidden = false;
  148. var currentValue = timeStep.current.valueOf();
  149. for (var i = 0; i < timeStep.hiddenDates.length; i++) {
  150. var startDate = timeStep.hiddenDates[i].start;
  151. var endDate = timeStep.hiddenDates[i].end;
  152. if (currentValue >= startDate && currentValue < endDate) {
  153. stepInHidden = true;
  154. break;
  155. }
  156. }
  157. if (stepInHidden == true && currentValue < timeStep._end.valueOf() && currentValue != previousTime) {
  158. var prevValue = moment(previousTime);
  159. var newValue = moment(endDate);
  160. if (prevValue.dayOfYear() != newValue.dayOfYear()) {
  161. timeStep.switchedDay = true;
  162. }
  163. timeStep.current = newValue.toDate();
  164. }
  165. };
  166. /**
  167. * Used in TimeStep to avoid the hidden times.
  168. * @param timeStep
  169. * @param previousTime
  170. */
  171. exports.checkFirstStep = function(timeStep) {
  172. var stepInHidden = false;
  173. var currentValue = timeStep.current.valueOf();
  174. for (var i = 0; i < timeStep.hiddenDates.length; i++) {
  175. var startDate = timeStep.hiddenDates[i].start;
  176. var endDate = timeStep.hiddenDates[i].end;
  177. if (currentValue >= startDate && currentValue < endDate) {
  178. stepInHidden = true;
  179. break;
  180. }
  181. }
  182. if (stepInHidden == true && currentValue <= timeStep._end.valueOf()) {
  183. var newValue = moment(endDate);
  184. timeStep.current = newValue.toDate();
  185. }
  186. };
  187. /**
  188. * replaces the Core toScreen methods
  189. * @param Core
  190. * @param time
  191. * @param width
  192. * @returns {number}
  193. */
  194. exports.toScreen = function(Core, time, width) {
  195. var hidden = exports.isHidden(time, Core.body.hiddenDates)
  196. if (hidden.hidden == true) {
  197. time = hidden.startDate;
  198. }
  199. var res = exports.correctTimeForDuration(Core.body.hiddenDates, Core.range, time);
  200. var duration = res.duration;
  201. time = res.time;
  202. var conversion = Core.range.conversion(width, duration);
  203. return (time.valueOf() - conversion.offset) * conversion.scale;
  204. };
  205. /**
  206. * Replaces the core toTime methods
  207. * @param body
  208. * @param range
  209. * @param x
  210. * @param width
  211. * @returns {Date}
  212. */
  213. exports.toTime = function(body, range, x, width) {
  214. var duration = exports.getHiddenDuration(body.hiddenDates, range);
  215. var conversion = range.conversion(width, duration);
  216. return new Date(x / conversion.scale + conversion.offset);
  217. };
  218. /**
  219. * Support function
  220. *
  221. * @param hiddenTimes
  222. * @param range
  223. * @returns {number}
  224. */
  225. exports.getHiddenDuration = function(hiddenTimes, range) {
  226. var duration = 0;
  227. for (var i = 0; i < hiddenTimes.length; i++) {
  228. var startDate = hiddenTimes[i].start;
  229. var endDate = hiddenTimes[i].end;
  230. // if time after the cutout, and the
  231. if (startDate >= range.start && endDate < range.end) {
  232. duration += endDate - startDate;
  233. }
  234. }
  235. return duration;
  236. };
  237. /**
  238. * Support function
  239. * @param hiddenTimes
  240. * @param range
  241. * @param time
  242. * @returns {{duration: number, time: *, offset: number}}
  243. */
  244. exports.correctTimeForDuration = function(hiddenTimes, range, time) {
  245. var duration = 0;
  246. var timeOffset = 0;
  247. time = moment(time).toDate().valueOf();
  248. for (var i = 0; i < hiddenTimes.length; i++) {
  249. var startDate = hiddenTimes[i].start;
  250. var endDate = hiddenTimes[i].end;
  251. // if time after the cutout, and the
  252. if (startDate >= range.start && endDate < range.end) {
  253. duration += (endDate - startDate);
  254. if (time >= endDate) {
  255. timeOffset += (endDate - startDate);
  256. }
  257. }
  258. }
  259. time -= timeOffset;
  260. return {duration: duration, time:time, offset: timeOffset};
  261. };
  262. /**
  263. * Used with zooming and dragging
  264. *
  265. * @param hiddenTimes
  266. * @param range
  267. * @param start
  268. * @param end
  269. * @param delta
  270. * @param zoom
  271. * @returns {*}
  272. */
  273. exports.snapAwayFromHidden = function(hiddenTimes, range, start, end, delta, zoom) {
  274. zoom = zoom || false;
  275. var newStart = start;
  276. var newEnd = end;
  277. var newDates = false;
  278. for (var i = 0; i < hiddenTimes.length; i++) {
  279. var startDate = hiddenTimes[i].start;
  280. var endDate = hiddenTimes[i].end;
  281. if (start >= startDate && start < endDate) { // if the start is entering a hidden zone
  282. newDates = true;
  283. // start from left, snap to right
  284. if (range.previousDelta - delta > 0 && zoom == false || zoom == true && range.previousDelta - delta < 0) { // from the left
  285. newStart = endDate + 1;
  286. }
  287. else { // start from right, snap to left
  288. newStart = startDate - 1;
  289. }
  290. }
  291. if (end >= startDate && end < endDate) { // if the end is entering a hidden zone
  292. newDates = true;
  293. if (range.previousDelta - delta < 0) { // end from right, snap to left
  294. newEnd = startDate - 1;
  295. }
  296. else { // end from left, snap to right
  297. newEnd = endDate + 1;
  298. }
  299. }
  300. }
  301. if (newDates == true) {
  302. range.deltaDifference += delta;
  303. return {newStart: newStart, newEnd: newEnd};
  304. }
  305. return false;
  306. };
  307. /**
  308. * Check if a time is hidden
  309. *
  310. * @param time
  311. * @param hiddenTimes
  312. * @returns {{hidden: boolean, startDate: Window.start, endDate: *}}
  313. */
  314. exports.isHidden = function(time, hiddenTimes) {
  315. var isHidden = false;
  316. for (var i = 0; i < hiddenTimes.length; i++) {
  317. var startDate = hiddenTimes[i].start;
  318. var endDate = hiddenTimes[i].end;
  319. if (time >= startDate && time < endDate) { // if the start is entering a hidden zone
  320. isHidden = true;
  321. break;
  322. }
  323. }
  324. return {hidden: isHidden, startDate: startDate, endDate: endDate};
  325. }