diff --git a/build/css/ox.ui.css b/build/css/ox.ui.css index 3b3a2537..0f6d4a38 100644 --- a/build/css/ox.ui.css +++ b/build/css/ox.ui.css @@ -119,6 +119,17 @@ Calendar overflow: hidden; } +.OxCalendar .OxBackground { + position: absolute; + top: 0; + bottom: 0; +} +.OxCalendar .OxBackground > div { + position: absolute; + top: 0; + bottom: 0; +} + .OxCalendar .OxLine { position: absolute; } @@ -131,12 +142,11 @@ Calendar white-space: nowrap; cursor: pointer; } -.OxCalendar .OxLine:nth-child(even) .OxDate { - background-color: rgb(255, 0, 0); -} -.OxCalendar .OxLine:nth-child(odd) .OxDate { - background-color: rgb(255, 64, 64); +.OxCalendar .OxLine > .OxDate { + background: -moz-linear-gradient(top, rgba(255, 64, 64, 0.75), rgba(255, 0, 0, 0.75)); + background: -webkit-gradient(linear, left top, left bottom, from(rgba(255, 32, 32, 1)), to(rgba(224, 0, 0, 1))); } + .OxCalendar .OxTimeline { position: absolute; height: 16px; diff --git a/build/css/ox.ui.modern.css b/build/css/ox.ui.modern.css index 8667e419..54d76125 100644 --- a/build/css/ox.ui.modern.css +++ b/build/css/ox.ui.modern.css @@ -37,16 +37,24 @@ Calendar ================================================================================ */ -.OxThemeModern .OxCalendar .OxTimeline > div.even { +.OxThemeModern .OxCalendar .OxTimeline > div.odd { background: -moz-linear-gradient(top, rgb(64, 64, 64), rgb(32, 32, 32)); - background: -webkit-gradient(linear, left top, left bottom, from(rgb(64, 64, 64)), to(rgb(32, 32, 32))); + background: -webkit-gradient(linear, left top, left bottom, from(rgb(64, 64, 64)), to(rgb(16, 16, 16))); } -.OxThemeModern .OxCalendar .OxTimeline > div.odd { - background: -moz-linear-gradient(top, rgb(56, 56, 56), rgb(24, 24, 24)); - background: -webkit-gradient(linear, left top, left bottom, from(rgb(56, 56, 56)), to(rgb(24, 24, 24))); +.OxThemeModern .OxCalendar .OxTimeline > div.even { + background: -moz-linear-gradient(top, rgb(48, 48, 48), rgb(24, 24, 24)); + background: -webkit-gradient(linear, left top, left bottom, from(rgb(48, 48, 48)), to(rgb(16, 16, 16))); } +.OxThemeModern .OxCalendar .OxBackground > div.odd { + background: rgb(16, 16, 16); +} +.OxThemeModern .OxCalendar .OxBackground > div.even { + background: rgb(24, 24, 24); +} + + /* ================================================================================ Dialog diff --git a/build/js/ox.ui.js b/build/js/ox.ui.js index 0e0c8d06..2edec10a 100644 --- a/build/js/ox.ui.js +++ b/build/js/ox.ui.js @@ -10968,7 +10968,8 @@ requires id: 'day', seconds: 86400, date: function(i) { - return i * 86400000; + // adjust for timezone difference + return i * 86400000 + +new Date().getTimezoneOffset() * 60000; }, name: function(i) { return Ox.formatDate(new Date(i * 86400000), '%b %e, %Y'); @@ -11025,6 +11026,7 @@ requires bottom: '40px' }) .bind({ + dblclick: dblclick, mouseleave: mouseleave, mousemove: mousemove, mousewheel: mousewheel @@ -11041,6 +11043,10 @@ requires .addClass('OxCalendarContent') .appendTo(self.$container); + self.$background = new Ox.Element() + .addClass('OxBackground') + .appendTo(self.$content); + self.$scalebar = new Ox.Element() .addClass('OxTimeline') .css({ @@ -11124,9 +11130,7 @@ requires textAlign: 'center' }); - sortDates(); - renderTimelines(); - renderDates(); + renderCalendar(); function changeDate() { @@ -11134,9 +11138,19 @@ requires function changeZoom(event, data) { self.options.zoom = data.value; - $('.OxDate').remove(); - renderTimelines(); - renderDates(); + renderCalendar(); + } + + function dblclick(e) { + if ($(e.target).is(':not(.OxLine > .OxDate)')) { + if (self.options.zoom < self.maxZoom) { + self.options.date = new Date( + (+self.options.date + +getMouseDate(e)) / 2 + ); + self.options.zoom++; + } + renderCalendar(); + } } function dragstart(event, e) { @@ -11147,34 +11161,50 @@ requires function drag(event, e) { if (self.drag) { + ///* self.$content.css({ marginLeft: (e.clientX - self.drag.x) + 'px' }); self.$scrollbar.css({ marginLeft: Math.round((e.clientX - self.drag.x) / 16) + 'px' - }); + }); + //*/ + /* + self.options.date = new Date( + +self.options.date - e.clientDX * getSecondsPerPixel() * 1000 + ); + */ + //self.drag = {x: e.clientX}; } } function dragpause(event, e) { - return; if (self.drag) { - Ox.print('dragpause') - dragafter(); + dragafter(e); self.drag = {x: e.clientX}; } } function dragend(event, e) { if (self.drag) { - self.options.date = new Date( - +self.options.date + (self.drag.x - e.clientX) * getSecondsPerPixel() * 1000 - ); + dragafter(e); self.drag = null; - dragafter(); } } + function dragafter(e) { + self.options.date = new Date( + +self.options.date - (e.clientX - self.drag.x) * getSecondsPerPixel() * 1000 + ); + self.$content.css({ + marginLeft: 0 + }); + self.$scrollbar.css({ + marginLeft: 0 + }); + renderCalendar(); + } + function dragstartScrollbar(event, e) { self.drag = {x: e.clientX}; } @@ -11189,33 +11219,27 @@ requires } function dragpauseScrollbar(event, e) { - return; + dragafterScrollbar(e); self.drag = {x: e.clientX}; - dragafter(); } function dragendScrollbar(event, e) { + dragafterScrollbar(e); + self.drag = null; + } + + function dragafterScrollbar(e) { self.options.date = new Date( +self.options.date + (self.drag.x - e.clientX) * getSecondsPerPixel() * 1000 * 16 ); - self.drag = null; - dragafter(); - } - - function dragafter() { + // fixme: duplicated self.$content.css({ marginLeft: 0 }); self.$scrollbar.css({ marginLeft: 0 }); - $('.OxDate').remove(); - renderTimelines(); - renderDates(); - var calendarDate = getCalendarDate(); - self.$statusbar.html( - calendarDate.start + ' | ' + self.options.date + ' | ' + calendarDate.stop - ); + renderCalendar(); } function formatDate(date) { @@ -11284,10 +11308,10 @@ requires } function getPosition(date, zoom) { - zoom = zoom || self.options.zoom return Math.round( self.options.width / 2 + - (date - self.options.date) / 1000 * getPixelsPerSecond(zoom) + (date - self.options.date) / 1000 * + getPixelsPerSecond(zoom || self.options.zoom) ); } @@ -11295,15 +11319,42 @@ requires return 1 / getPixelsPerSecond(zoom); } + function getBackgroundElements(zoom) { + // fixme: duplicated + var $elements = [], + pixelsPerSecond = getPixelsPerSecond(zoom), + n, unit, value, width; + Ox.forEach(self.units, function(v, i) { + width = Math.round(v.seconds * pixelsPerSecond); + if (width < 64) { + unit = v; + return false; + } + }); + n = Math.ceil(self.options.width * 1.5/* * 16*/ / width); + value = unit.value(self.options.date); + Ox.loop(-n, n + 1, function(i) { + $elements.push( + new Ox.Element() + .addClass(Ox.mod(value + i, 2) == 0 ? 'even' : 'odd') + .css({ + left: getPosition(new Date(unit.date(value + i)), zoom) + 'px', + width: width + 'px' + }) + ); + }); + return $elements; + } + function getTimelineElements(zoom) { var $elements = [], pixelsPerSecond = getPixelsPerSecond(zoom), n, unit, value, width; self.units = self.units.reverse(); Ox.forEach(self.units, function(v) { - width = v.seconds * pixelsPerSecond; + width = Math.round(v.seconds * pixelsPerSecond); if (width >= 64) { - unit = Ox.getObjectById(self.units, v.id); + unit = v; return false; } }); @@ -11313,7 +11364,7 @@ requires Ox.loop(-n, n + 1, function(i) { $elements.push( getDateElement({ - name: unit.name(value + i)/* + unit.date(value + i) + '-' + unit.date(value + i + 1)*/, + name: unit.name(value + i), start: new Date(unit.date(value + i)), stop: new Date(unit.date(value + i + 1)) }, zoom) @@ -11344,18 +11395,22 @@ requires } function mousewheel(e, delta, deltaX, deltaY) { - Ox.print('mousewheel', delta, deltaX, deltaY); + //Ox.print('mousewheel', delta, deltaX, deltaY); + var deltaZ = 0; if (!self.mousewheel && deltaY && Math.abs(deltaY) > Math.abs(deltaX)) { - self.options.date = deltaY < 0 ? - new Date(2 * +self.options.date - +getMouseDate(e)) : - new Date((+self.options.date + +getMouseDate(e)) / 2) - self.options.zoom = Ox.limit(self.options.zoom + ( - deltaY < 0 ? -1 : 1 - ), 0, self.maxZoom); - self.$zoomInput.options({value: self.options.zoom}); - $('.OxDate').remove(); - renderTimelines(); - renderDates(); + if (deltaY < 0 && self.options.zoom > 0) { + deltaZ = -1 + } else if (deltaY > 0 && self.options.zoom < self.maxZoom) { + deltaZ = 1 + } + if (deltaZ) { + self.options.date = deltaZ == -1 ? + new Date(2 * +self.options.date - +getMouseDate(e)) : + new Date((+self.options.date + +getMouseDate(e)) / 2) + self.options.zoom += deltaZ; + self.$zoomInput.options({value: self.options.zoom}); + renderCalendar(); + } } self.mousewheel = true; setTimeout(function() { @@ -11371,14 +11426,37 @@ requires ); } + function renderCalendar() { + $('.OxBackground').empty(); + $('.OxDate').remove(); + renderBackground(); + renderTimelines(); + renderDates(); + } + + function renderBackground() { + getBackgroundElements(self.options.zoom).forEach(function($element) { + $element.appendTo(self.$background); + }); + } + function renderDates() { - self.lineDates = []; - self.$lines = []; - self.options.dates.forEach(function(date, i) { - var line = self.$lines.length; - Ox.forEach(self.lineDates, function(dates, line_) { + var calendarDate = getCalendarDate(); + lineDates = []; + self.options.dates.filter(function(date) { + // filter out dates outside the visible area + return overlaps(date, calendarDate); + }).sort(function(a, b) { + // sort dates by duration, descending + return (b.stop - b.start) - (a.stop - a.start); + }).forEach(function(date, i) { + var line = lineDates.length; + // traverse lines + Ox.forEach(lineDates, function(dates, line_) { var fits = true; + // traverse dates in line Ox.forEach(dates, function(date_) { + // if overlaps, check next line if (overlaps(date, date_)) { fits = false; return false; @@ -11389,24 +11467,30 @@ requires return false; } }); - if (line == self.$lines.length) { - self.lineDates[line] = []; - self.$lines[line] = new Ox.Element() - .addClass('OxLine') - .css({ - top: ((line + 1) * 16) + 'px' - }); + if (line == lineDates.length) { + lineDates[line] = []; } - self.lineDates[line].push(date); - self.$lines[line].append(getDateElement(date)); + lineDates[line].push(date); }); $('.OxLine').remove(); - self.$lines.forEach(function($line) { - $line.appendTo(self.$content); + lineDates.forEach(function(dates, line) { + var $line = new Ox.Element() + .addClass('OxLine') + .css({ + top: ((line + 1) * 16) + 'px' + }) + .appendTo(self.$content); + dates.sort(function(a, b) { + // sort dates by start, ascending + return a.start - b.start; + }).forEach(function(date) { + getDateElement(date).appendTo($line); + }); }); } function renderTimelines() { + Ox.print(self.options.zoom, Math.max(self.options.zoom - 4, 0)) getTimelineElements(self.options.zoom).forEach(function($element) { $element.appendTo(self.$scalebar.$element); }); @@ -11415,12 +11499,6 @@ requires }); } - function sortDates() { - self.options.dates.sort(function(a, b) { - return (b.stop - b.start) - (a.stop - a.start); - }); - } - self.onChange = function(key, val) { if (key == 'date') { diff --git a/demos/calendar/js/calendar.js b/demos/calendar/js/calendar.js index d644c9b5..3e7fec8d 100644 --- a/demos/calendar/js/calendar.js +++ b/demos/calendar/js/calendar.js @@ -5,8 +5,41 @@ $(function() { new Ox.Calendar({ date: new Date(0), dates: [ + {name: 'Genghis Khan', start: new Date('1162'), stop: new Date('1228'), type: 'Person'}, + {name: 'Columbus', start: new Date('1451-08-22'), stop: new Date('1506-05-21'), type: 'Person'}, + {name: 'Da Vinci', start: new Date('1452-04-15'), stop: new Date('1519-05-03'), type: 'Person'}, + {name: 'Michelangelo', start: new Date('1475-03-06'), stop: new Date('1564-02-19'), type: 'Person'}, + {name: 'Bruegel', start: new Date('1525'), stop: new Date('1569-09-10'), type: 'Person'}, + {name: 'Galilei', start: new Date('1564-02-15'), stop: new Date('1642-01-09'), type: 'Person'}, + {name: 'Shakespeare', start: new Date('1564-04-26'), stop: new Date('1616-04-24'), type: 'Person'}, + {name: 'Descartes', start: new Date('1596-03-31'), stop: new Date('1650-02-12'), type: 'Person'}, + {name: 'Velazquez', start: new Date('1599-06-06'), stop: new Date('1660-08-07'), type: 'Person'}, + {name: 'Vermeer', start: new Date('1632-10-31'), stop: new Date('1675-12-16'), type: 'Person'}, + {name: 'Spinoza', start: new Date('1632-11-24'), stop: new Date('1677-02-22'), type: 'Person'}, + {name: 'Louix XIV', start: new Date('1638-09-05'), stop: new Date('1715-09-02'), type: 'Person'}, + {name: 'Newton', start: new Date('1643-01-04'), stop: new Date('1727-04-01'), type: 'Person'}, + {name: 'Leibniz', start: new Date('1646-07-01'), stop: new Date('1716-11-15'), type: 'Person'}, + {name: 'Kant', start: new Date('1724-04-22'), stop: new Date('1804-02-13'), type: 'Person'}, + {name: 'Napoleon', start: new Date('1769-08-15'), stop: new Date('1821-05-06'), type: 'Person'}, + {name: 'Hegel', start: new Date('1770-08-27'), stop: new Date('1831-11-15'), type: 'Person'}, + {name: 'Darwin', start: new Date('1809-02-12'), stop: new Date('1882-04-20'), type: 'Person'}, + {name: 'Marx', start: new Date('1818-05-05'), stop: new Date('1883-03-15'), type: 'Person'}, + /* + {name: 'Lenin', start: new Date('1870-04-22'), stop: new Date('1924-01-22'), type: 'Person'}, + {name: 'Stalin', start: new Date('1878-12-18'), stop: new Date('1953-03-06'), type: 'Person'}, + {name: 'Einstein', start: new Date('1879-03-14'), stop: new Date('1955-04-19'), type: 'Person'}, + {name: 'Picasso', start: new Date('1881-10-25'), stop: new Date('1973-04-09'), type: 'Person'}, + {name: 'Hitler', start: new Date('1889-04-20'), stop: new Date('1945-05-01'), type: 'Person'}, + {name: 'Hitchcock', start: new Date('1899-08-13'), stop: new Date('1980-04-30'), type: 'Person'}, + {name: 'Turing', start: new Date('1912-06-23'), stop: new Date('1954-06-08'), type: 'Person'}, + {name: 'Deleuze', start: new Date('1925-01-18'), stop: new Date('1995-11-05'), type: 'Person'}, + {name: 'Warhol', start: new Date('1928-08-06'), stop: new Date('1987-02-23'), type: 'Person'}, + {name: 'Debord', start: new Date('1931-12-28'), stop: new Date('1994-12-01'), type: 'Person'}, + */ + {name: 'Test', start: new Date('1970-01-01'), stop: new Date('1970-01-02')}, {name: 'Battle of Hastings', start: new Date('1066-10-14'), stop: new Date('1066-10-15')}, {name: 'Renaissance', start: new Date('1300'), stop: new Date('1700')}, + {name: 'Discovery of America', start: new Date('1492'), stop: new Date('1493')}, {name: 'Thirty Years\' War', start: new Date('1618'), stop: new Date('1649')}, {name: 'Declaration of Independence', start: new Date('1776-07-04'), stop: new Date('1776-07-05')}, {name: 'French Revolution', start: new Date('1789'), stop: new Date('1800')}, @@ -17,9 +50,11 @@ $(function() { {name: 'Franco-Prussian War', start: new Date('1870-07-19'), stop: new Date('1871-05-11')}, {name: 'Paris Commune', start: new Date('1871-03-18'), stop: new Date('1871-05-29')}, {name: '20th century', start: new Date('1900'), stop: new Date('2000')}, + {name: 'Titanic', start: new Date('1912-04-15'), stop: new Date('1912-04-16')}, {name: 'World War One', start: new Date('1914-07-28'), stop: new Date('1918-11-12')}, {name: 'Russian Revolution', start: new Date('1917'), stop: new Date('1918')}, {name: 'October Revolution', start: new Date('1917-11-07'), stop: new Date('1917-11-09')}, + {name: 'Spanish Flu', start: new Date('1918'), stop: new Date('1919')}, {name: 'Weimar Republic', start: new Date('1918-11-09'), stop: new Date('1933-01-30')}, {name: 'Treaty of Versailles', start: new Date('1919-06-28'), stop: new Date('1919-06-29')}, {name: '1920s', start: new Date('1920'), stop: new Date('1930')}, @@ -27,10 +62,12 @@ $(function() { {name: 'The Third Reich', start: new Date('1933-01-30'), stop: new Date('1945-05-09')}, {name: 'Spanish Civil War', start: new Date('1936-07-17'), stop: new Date('1939-04-02')}, {name: '1936 Summer Olympics', start: new Date('1936-08-01'), stop: new Date('1936-08-17')}, + {name: 'Hindenburg', start: new Date('1937-05-06'), stop: new Date('1937-05-07')}, {name: 'World War Two', start: new Date('1939-09-01'), stop: new Date('1945-09-03')}, {name: 'Wannsee Conference', start: new Date('1942-01-20'), stop: new Date('1942-01-21')}, {name: 'Hiroshima', start: new Date('1945-08-06'), stop: new Date('1945-08-07')}, {name: 'Nagasaki', start: new Date('1945-08-09'), stop: new Date('1945-08-10')}, + {name: 'Nuremburg Trials', start: new Date('1945-11-20'), stop: new Date('1946-10-02')}, {name: 'West Germany', start: new Date('1949-05-23'), stop: new Date('1990-10-03')}, {name: 'Korean War', start: new Date('1950-06-25'), stop: new Date('1953-07-28')}, {name: 'Cuban Revolution', start: new Date('1953-07-26'), stop: new Date('1959-01-02')}, @@ -53,12 +90,14 @@ $(function() { {name: '1968 Cannes Film Festival', start: new Date('1968-05-10'), stop: new Date('1968-05-20')}, {name: 'Valerie Solanas', start: new Date('1968-06-03'), stop: new Date('1968-06-04')}, {name: 'Assassination of Robert F. Kennedy', start: new Date('1968-06-05'), stop: new Date('1968-06-06')}, + {name: '1968 Summer Olympics', start: new Date('1968-10-12'), stop: new Date('1968-10-28')}, {name: 'Apollo 11', start: new Date('1969-07-16'), stop: new Date('1969-07-25')}, {name: 'Moon Landing', start: new Date('1969-07-20'), stop: new Date('1969-07-21')}, {name: 'The Epoch', start: new Date('1970-01-01 00:00:00'), stop: new Date('1970-01-01 00:00:01')}, {name: '1970s', start: new Date('1970-01-01'), stop: new Date('1980-01-01')}, {name: '1972 Summer Olympics', start: new Date('1972-08-26'), stop: new Date('1972-09-11')}, {name: 'Apollo 17', start: new Date('1972-12-07'), stop: new Date('1972-12-20')}, + {name: 'World Trade Center', start: new Date('1973-04-04'), stop: new Date('2001-09-11')}, {name: '1980s', start: new Date('1980-01-01'), stop: new Date('1990-01-01')}, {name: 'Iran-Iraq War', start: new Date('1980-09-22'), stop: new Date('1988-08-21')}, {name: 'Tschernobyl', start: new Date('1986-04-26'), stop: new Date('1986-04-27')},