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.

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