diff --git a/demos/calendar/js/calendar.js b/demos/calendar/js/calendar.js index 5f2c01cb..27bf0c3a 100644 --- a/demos/calendar/js/calendar.js +++ b/demos/calendar/js/calendar.js @@ -44,15 +44,18 @@ Ox.load('UI', {debug: true, hideScreen: true, showScreen: true, theme: 'modern'} {name: '2020s', start: '2020', end: '2030', type: 'date'}, + {name: 'Barbarossa', start: '1122', end: '1190-06-10', type: 'person'}, {name: 'Genghis Khan', start: '1162', end: '1228', type: 'person'}, {name: 'Marco Polo', start: '1254', end: '1324-01-08', type: 'person'}, {name: 'Christopher Columbus', start: '1451-08-22', end: '1506-05-20', type: 'person'}, {name: 'Leonardo da Vinci', start: '1452-04-15', end: '1519-05-02', type: 'person'}, {name: 'Michelangelo', start: '1475-03-06', end: '1564-02-18', type: 'person'}, {name: 'Pieter Bruegel', start: '1525', end: '1569-09-09', type: 'person'}, + {name: 'Francis Bacon', start: '1561-01-22', end: '1626-04-09', type: 'person'}, {name: 'Galileo Galilei', start: '1564-02-15', end: '1642-01-08', type: 'person'}, {name: 'William Shakespeare', start: '1564-04-26', end: '1616-04-23', type: 'person'}, {name: 'René Descartes', start: '1596-03-31', end: '1650-02-11', type: 'person'}, + {name: 'Oliver Cromwell', start: '1599-04-25', end: '1658-09-03', type: 'person'}, {name: 'Diego Velázquez', start: '1599-06-06', end: '1660-08-06', type: 'person'}, {name: 'Johannes Vermeer', start: '1632-10-31', end: '1675-12-15', type: 'person'}, {name: 'Baruch Spinoza', start: '1632-11-24', end: '1677-02-21', type: 'person'}, @@ -92,6 +95,7 @@ Ox.load('UI', {debug: true, hideScreen: true, showScreen: true, theme: 'modern'} {name: 'Adolf Hitler', start: '1889-04-20', end: '1945-04-30', type: 'person'}, {name: 'Charles de Gaulle', start: '1890-11-22', end: '1970-11-09', type: 'person'}, {name: 'Walter Benjamin', start: '1892-07-15', end: '1940-09-26', type: 'person'}, + {name: 'Mao Zedong', start: '1893-12-26', end: '1976-09-09', type: 'person'}, {name: 'Al Capone', start: '1899-01-17', end: '1947-01-25', type: 'person'}, {name: 'Alfred Hitchcock', start: '1899-08-13', end: '1980-04-29', type: 'person'}, {name: 'Werner Heisenberg', start: '1901-12-05', end: '1976-02-01', type: 'person'}, @@ -103,6 +107,7 @@ Ox.load('UI', {debug: true, hideScreen: true, showScreen: true, theme: 'modern'} {name: 'Alan Turing', start: '1912-06-23', end: '1954-06-07', type: 'person'}, {name: 'John F. Kennedy', start: '1917-05-29', end: '1963-11-22', type: 'person'}, {name: 'Gilles Deleuze', start: '1925-01-18', end: '1995-11-04', type: 'person'}, + {name: 'Pol Pot', start: '1925-05-19', end: '1998-04-15', type: 'person'}, {name: 'Marylin Monroe', start: '1926-06-01', end: '1962-08-05', type: 'person'}, {name: 'Michel Foucault', start: '1926-10-15', end: '1984-06-25', type: 'person'}, {name: 'Che Guevara', start: '1928-06-14', end: '1967-10-09', type: 'person'}, @@ -200,6 +205,7 @@ Ox.load('UI', {debug: true, hideScreen: true, showScreen: true, theme: 'modern'} ], height: window.innerHeight, + range: [-5000, 5000], width: window.innerWidth, zoom: 4 }).appendTo(Ox.UI.$body).gainFocus(); diff --git a/source/Ox.UI/css/Ox.UI.css b/source/Ox.UI/css/Ox.UI.css index 1bbfc774..cf02088b 100644 --- a/source/Ox.UI/css/Ox.UI.css +++ b/source/Ox.UI/css/Ox.UI.css @@ -196,7 +196,11 @@ Calendar cursor: ew-resize; } .OxCalendar .OxOverlay div:nth-child(odd) { - background-color: rgba(0, 0, 0, 0.333); + background-color: rgba(0, 0, 0, 0.75); +} + +.OxCalendar .OxRange .OxArrow { + border-radius: 0; } diff --git a/source/Ox.UI/js/Calendar/Ox.Calendar.js b/source/Ox.UI/js/Calendar/Ox.Calendar.js index 5b638d63..a61278f6 100644 --- a/source/Ox.UI/js/Calendar/Ox.Calendar.js +++ b/source/Ox.UI/js/Calendar/Ox.Calendar.js @@ -15,7 +15,7 @@ Ox.Calendar Basic calendar object start Start of the event (UTC Date, as string) type Type of the event (like "person") height Height in px - range <[n]|[100, 5101]> Start and end year of the calendar + range <[n]|[1000, 3000]> Start and end year of the calendar selected Id of the selected event width Width in px zoom Initial zoom level @@ -46,8 +46,8 @@ Ox.Calendar = function(options, self) { height: self.options.height + 'px' }) .bindEvent({ - anyclick: function() { - that.gainFocus(); + anyclick: function(e) { + !$(e.target).is('.OxInput') && that.gainFocus(); }, key_0: function() { panToSelected(); @@ -80,21 +80,19 @@ Ox.Calendar = function(options, self) { self.maxZoom = 32; self.minLabelWidth = 80; - self.overlayWidths = [Math.round(self.options.width / 16)]; - self.overlayWidths = [ - Math.floor((self.options.width - self.overlayWidths[0]) / 2), - self.overlayWidths[0], - Math.ceil((self.options.width - self.overlayWidths[0]) / 2), - ]; self.units = [ { id: 'millennium', seconds: 365242.5 * 86400, date: function(i) { - return '01/01/' + (i + 1) + '000 UTC'; + var date = new Date(1970, 0, 1); + date.setUTCFullYear((i + 1) * 1000); + return date; }, name: function(i) { - return Ox.formatOrdinal(i + 2) + ' millennium'; + return i > -2 + ? Ox.formatOrdinal(i + 2) + ' millennium' + : Ox.formatOrdinal(-i - 1) + ' millennium BC' }, value: function(date) { return Math.floor(date.getUTCFullYear() / 1000) - 1; @@ -104,10 +102,14 @@ Ox.Calendar = function(options, self) { id: 'century', seconds: 36524.25 * 86400, date: function(i) { - return '01/01/' + (i + 19) + '00 UTC'; + var date = new Date(1970, 0, 1); + date.setUTCFullYear((i + 19) * 100); + return date; }, name: function(i) { - return Ox.formatOrdinal(i + 20) + ' century'; + return i > -20 + ? Ox.formatOrdinal(i + 20) + ' century' + : Ox.formatOrdinal(-i - 19) + ' century BC' }, value: function(date) { return Math.floor(date.getUTCFullYear() / 100) - 19; @@ -117,7 +119,9 @@ Ox.Calendar = function(options, self) { id: 'decade', seconds: 3652.425 * 86400, date: function(i) { - return '01/01/' + (i + 197) + '0 UTC' + var date = new Date(1970, 0, 1); + date.setUTCFullYear((i + 197) * 10); + return date; }, name: function(i) { return (i + 197) + '0s' @@ -143,7 +147,9 @@ Ox.Calendar = function(options, self) { id: 'month', seconds: 365.2425 / 12 * 86400, date: function(i) { - return (Ox.mod(i, 12) + 1) + '/01/' + (Math.floor(i / 12) + 1970) + ' UTC'; + var date = new Date(1970, Ox.mod(i, 12), 1); + date.setUTCFullYear(Math.floor(i / 12) + 1970) + return date; }, name: function(i) { return Ox.SHORT_MONTHS[Ox.mod(i, 12)] + ' ' + Math.floor(i / 12 + 1970) @@ -156,7 +162,7 @@ Ox.Calendar = function(options, self) { id: 'week', seconds: 7 * 86400, date: function(i) { - return (i * 7 - 3) * 86400000; + return new Date((i * 7 - 3) * 86400000); }, name: function(i) { return Ox.formatDate(new Date((i * 7 - 3) * 86400000), '%a, %b %e'); @@ -169,7 +175,7 @@ Ox.Calendar = function(options, self) { id: 'day', seconds: 86400, date: function(i) { - return i * 86400000; + return new Date(i * 86400000); }, name: function(i) { return Ox.formatDate(new Date(i * 86400000), '%b %e, %Y', true); @@ -182,7 +188,7 @@ Ox.Calendar = function(options, self) { id: 'six_hours', seconds: 21600, date: function(i) { - return i * 21600000; + return new Date(i * 21600000); }, name: function(i) { return Ox.formatDate(new Date(i * 21600000), '%b %e, %H:00', true); @@ -195,7 +201,7 @@ Ox.Calendar = function(options, self) { id: 'hour', seconds: 3600, date: function(i) { - return i * 3600000; + return new Date(i * 3600000); }, name: function(i) { return Ox.formatDate(new Date(i * 3600000), '%b %e, %H:00', true); @@ -208,7 +214,7 @@ Ox.Calendar = function(options, self) { id: 'five_minutes', seconds: 300, date: function(i) { - return i * 300000; + return new Date(i * 300000); }, name: function(i) { return Ox.formatDate(new Date(i * 300000), '%b %e, %H:%M', true); @@ -221,7 +227,7 @@ Ox.Calendar = function(options, self) { id: 'minute', seconds: 60, date: function(i) { - return i * 60000; + return new Date(i * 60000); }, name: function(i) { return Ox.formatDate(new Date(i * 60000), '%b %e, %H:%M', true); @@ -234,7 +240,7 @@ Ox.Calendar = function(options, self) { id: 'five_seconds', seconds: 5, date: function(i) { - return i * 5000; + return new Date(i * 5000); }, name: function(i) { return Ox.formatDate(new Date(i * 5000), '%H:%M:%S', true); @@ -247,7 +253,7 @@ Ox.Calendar = function(options, self) { id: 'second', seconds: 1, date: function(i) { - return i * 1000; + return new Date(i * 1000); }, name: function(i) { return Ox.formatDate(new Date(i * 1000), '%H:%M:%S', true); @@ -263,7 +269,6 @@ Ox.Calendar = function(options, self) { }) .appendTo(that); - Ox.print(self.options.showTypes) self.$typeSelect = Ox.Select({ items: [ {id: 'date', title: 'Dates', checked: self.options.showTypes.indexOf('date') > -1}, @@ -276,7 +281,7 @@ Ox.Calendar = function(options, self) { title: 'Show...', width: 80 }) - .css({margin: '4px'}) + .css({float: 'left', margin: '4px'}) .bindEvent({ change: function(data) { self.options.showTypes = data.selected.map(function(type) { @@ -287,11 +292,25 @@ Ox.Calendar = function(options, self) { }) .appendTo(self.$toolbar); + self.$dateInput = Ox.Input({ + clear: true, + //placeholder: 'Date', + value: Ox.formatDate(self.options.date, '%Y-%m-%d %H:%M:%S', true), + width: 160 + }) + .css({float: 'right', margin: '4px'}) + .bindEvent({ + change: function(data) { + panTo(Ox.parseDate(data.value, true)) + } + }) + .appendTo(self.$toolbar); + self.$container = new Ox.Element() .addClass('OxCalendarContainer') .css({ top: '24px', - bottom: '40px' + bottom: '16px' }) .bind({ mouseleave: mouseleave, @@ -327,46 +346,18 @@ Ox.Calendar = function(options, self) { .addClass('OxTimeline') .css({ posision: 'absolute', - bottom: '40px' - }) - .appendTo(that); - self.$overlay = new Ox.Element() - .addClass('OxOverlay') - .css({ - bottom: '40px' - }) - .append( - $('
').css({ - width: self.overlayWidths[0] + 'px' - }) - ) - .append( - $('
').css({ - left: self.overlayWidths[0] + 'px', - width: self.overlayWidths[1] + 'px' - }) - ) - .append( - $('
').css({ - left: (self.overlayWidths[0] + self.overlayWidths[1]) + 'px', - width: self.overlayWidths[2] + 'px' - }) - ) - .bindEvent({ - dragstart: dragstartScrollbar, - drag: dragScrollbar, - dragpause: dragpauseScrollbar, - dragend: dragendScrollbar + bottom: '16px' }) .appendTo(that); self.$zoombar = new Ox.Element() .css({ position: 'absolute', - bottom: 24 + 'px', + bottom: 0, height: '16px' }) .appendTo(that); + self.$zoomInput = new Ox.Range({ arrows: true, max: self.maxZoom, @@ -381,17 +372,6 @@ Ox.Calendar = function(options, self) { }) .appendTo(self.$zoombar); - self.$statusbar = new Ox.Bar({ - size: 24 - }) - .css({ - // fixme: no need to set position absolute with map statusbar - position: 'absolute', - bottom: 0, - textAlign: 'center' - }) - .appendTo(that); - self.$tooltip = new Ox.Tooltip({ animate: false }) @@ -423,9 +403,9 @@ Ox.Calendar = function(options, self) { } function dragstart(event, e) { - if ($(e.target).is(':not(.OxLine > .OxEvent)')) { + //if ($(e.target).is(':not(.OxLine > .OxEvent)')) { self.drag = {x: e.clientX}; - } + //} } function drag(event, e) { @@ -480,7 +460,7 @@ Ox.Calendar = function(options, self) { function dragScrollbar(event, e) { self.$content.css({ - marginLeft: ((e.clientX - self.drag.x) * 16) + 'px' + marginLeft: ((e.clientX - self.drag.x) * getScrollbarFactor()) + 'px' }); self.$scrollbar.css({ marginLeft: (e.clientX - self.drag.x) + 'px' @@ -556,7 +536,7 @@ Ox.Calendar = function(options, self) { } function getCalendarEvent(zoom) { - var ms = self.options.width * getSecondsPerPixel(zoom || self.options.zoom) * 1000; + var ms = self.options.width * getSecondsPerPixel(zoom) * 1000; return { start: new Date(+self.options.date - ms / 2), end: new Date(+self.options.date + ms / 2) @@ -621,18 +601,33 @@ Ox.Calendar = function(options, self) { ) * getSecondsPerPixel() * 1000); } + function getOverlayWidths() { + var width = Math.round(self.options.width / getScrollbarFactor()); + return [ + Math.floor((self.options.width - width) / 2), + width, + Math.ceil((self.options.width - width) / 2), + ]; + } + function getPixelsPerSecond(zoom) { - return Math.pow(2, (zoom || self.options.zoom) - (self.maxZoom - 4)); + return Math.pow(2, ( + !Ox.isUndefined(zoom) ? zoom : self.options.zoom + ) - (self.maxZoom - 4)); } function getPosition(date, zoom) { return Math.round( self.options.width / 2 + (date - self.options.date) / 1000 * - getPixelsPerSecond(zoom || self.options.zoom) + getPixelsPerSecond(zoom) ); } + function getScrollbarFactor() { + return Math.pow(2, Math.min(self.options.zoom, 4)); + } + function getSecondsPerPixel(zoom) { return 1 / getPixelsPerSecond(zoom); } @@ -662,7 +657,7 @@ Ox.Calendar = function(options, self) { u == 0 ? 'line' : Ox.mod(value + i, 2) == 0 ? 'even' : 'odd' ) .css({ - left: getPosition(new Date(unit.date(value + i)), zoom) + 'px', + left: getPosition(unit.date(value + i), zoom) + 'px', width: (u == 0 ? 1 : width) + 'px' }) ); @@ -675,14 +670,15 @@ Ox.Calendar = function(options, self) { var $elements = [], unit = getUnits(zoom)[0], value = unit.value(self.options.date), - width = unit.seconds * getPixelsPerSecond(zoom); + width = unit.seconds * getPixelsPerSecond(zoom), n = Math.ceil(self.options.width * 1.5/* * 16*/ / width); + Ox.print(zoom, getUnits(zoom).map(function(u) {return u.name(value)}).join('/')) Ox.loop(-n, n + 1, function(i) { $elements.push( getEventElement({ name: unit.name(value + i), - start: new Date(unit.date(value + i)), - end: new Date(unit.date(value + i + 1)) + start: unit.date(value + i), + end: unit.date(value + i + 1) }, zoom) .addClass(Ox.mod(value + i, 2) == 0 ? 'even' : 'odd') ); @@ -696,7 +692,8 @@ Ox.Calendar = function(options, self) { // units[1] for background var pixelsPerSecond = getPixelsPerSecond(zoom), units; - self.units = self.units.reverse(); + Ox.print(zoom, 'ppsec', pixelsPerSecond) + self.units.reverse(); Ox.forEach(self.units, function(v, i) { width = Math.round(v.seconds * pixelsPerSecond); if (width >= self.minLabelWidth) { @@ -704,7 +701,7 @@ Ox.Calendar = function(options, self) { return false; } }); - self.units = self.units.reverse(); + self.units.reverse(); return units; } @@ -795,10 +792,11 @@ Ox.Calendar = function(options, self) { $('.OxEvent').remove(); renderBackground(); renderTimelines(); + renderOverlay(); renderEvents(); - self.$statusbar.html( - Ox.formatDate(self.options.date, '%a, %b %e, %Y, %H:%M:%S (%s)', true) - ); + self.$dateInput.options({ + value: Ox.formatDate(self.options.date, '%Y-%m-%d %H:%M:%S', true) + }); } function renderEvents() { @@ -842,7 +840,7 @@ Ox.Calendar = function(options, self) { } lineEvents[line].push(event); }); - $('.OxLine').remove(); + self.$content.find('.OxLine').remove(); lineEvents.forEach(function(events, line) { var $line = new Ox.Element() .addClass('OxLine') @@ -859,6 +857,40 @@ Ox.Calendar = function(options, self) { }); } + function renderOverlay() { + var widths = getOverlayWidths(); + that.find('.OxOverlay').remove(); + Ox.Element() + .addClass('OxOverlay') + .css({ + bottom: '16px' + }) + .append( + $('
').css({ + width: widths[0] + 'px' + }) + ) + .append( + $('
').css({ + left: widths[0] + 'px', + width: widths[1] + 'px' + }) + ) + .append( + $('
').css({ + left: (widths[0] + widths[1]) + 'px', + width: widths[2] + 'px' + }) + ) + .bindEvent({ + dragstart: dragstartScrollbar, + drag: dragScrollbar, + dragpause: dragpauseScrollbar, + dragend: dragendScrollbar + }) + .appendTo(that); + } + function renderTimelines() { Ox.print(self.options.zoom, Math.max(self.options.zoom - 4, 0)) getTimelineElements(self.options.zoom).forEach(function($element) {