From ef66521e9ea77fe476a0e02dc352c8afeb695c9d Mon Sep 17 00:00:00 2001 From: "ronp@winter" Date: Thu, 26 Dec 2013 11:04:54 +0200 Subject: [PATCH 1/5] Fixed handling of as interval. This helps in sequences that last only a minute or two, like a sports event or a malware attack sequence --- source/js/VMM.Timeline.TimeNav.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/js/VMM.Timeline.TimeNav.js b/source/js/VMM.Timeline.TimeNav.js index 576f1913c..5e4c52213 100644 --- a/source/js/VMM.Timeline.TimeNav.js +++ b/source/js/VMM.Timeline.TimeNav.js @@ -554,7 +554,7 @@ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefin interval_calc.minute.minor = 60; // SECOND - interval_calc.second.type = "decade"; + interval_calc.second.type = "second"; interval_calc.second.first = _first.seconds; interval_calc.second.base = Math.floor(_first.seconds); interval_calc.second.last = _last.seconds; @@ -643,6 +643,8 @@ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefin timerelative.start = _first.hours; } else if (_type == "minute") { timerelative.start = _first.minutes; + } else if (_type == "second") { + timerelative.start = _first.seconds; } /* LAST @@ -678,6 +680,8 @@ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefin timerelative.end = _last.hours; } else if (_type == "minute") { timerelative.end = _last.minutes; + } else if (_type == "second") { + timerelative.end = _last.seconds; } } else { From 6e50f1b37d48bc7034c2cbfa4c24e22958f30778 Mon Sep 17 00:00:00 2001 From: "ronp@winter" Date: Thu, 26 Dec 2013 11:46:19 +0200 Subject: [PATCH 2/5] added control over swimlanes in TimeNav. Up until now adding a tag to a Thu Dec 26 11:46:19 IST 2013 section puts this event in an annotated swimlane. however the swimlanes are arranged according to first-come. Adding a tags list (optional) allows to control the vertical arrangments of these lanes --- README.markdown | 12 ++++++++++++ source/js/VMM.Timeline.TimeNav.js | 7 ++++--- source/js/VMM.Timeline.js | 4 ++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/README.markdown b/README.markdown index 13457e58e..da589f83a 100644 --- a/README.markdown +++ b/README.markdown @@ -255,6 +255,10 @@ JSON is the native data format for TimelineJS. Remember, JSON is picky. A misplaced comma or quotation mark can prevent the timeline from loading properly. +Note that optional tags on events (dates) puts them in an annotated `swimlane` +in the TimeNav. Adding the `tags` list to the JSON file allows you to control +the order of these swimlanes. + Here is the full model: ```javascript @@ -269,6 +273,10 @@ Here is the full model: "credit":"Credit Name Goes Here", "caption":"Caption text goes here" }, + "tags": [ + "optional", + "list" + ], "date": [ { "startDate":"2011,12,10", @@ -318,6 +326,10 @@ storyjs_jsonp_data = { "credit":"Credit Name Goes Here", "caption":"Caption text goes here" }, + "tags": [ + "optional", + "list" + ], "date": [ { "startDate":"2011,12,10", diff --git a/source/js/VMM.Timeline.TimeNav.js b/source/js/VMM.Timeline.TimeNav.js index 5e4c52213..19ff7331e 100644 --- a/source/js/VMM.Timeline.TimeNav.js +++ b/source/js/VMM.Timeline.TimeNav.js @@ -137,12 +137,12 @@ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefin /* INIT ================================================== */ - this.init = function(d,e) { + this.init = function(d,e,t) { trace('VMM.Timeline.TimeNav init'); // need to evaluate d // some function to determine type of data and prepare it if(typeof d != 'undefined') { - this.setData(d, e); + this.setData(d, e, t); } else { trace("WAITING ON DATA"); } @@ -150,11 +150,12 @@ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefin /* GETTERS AND SETTERS ================================================== */ - this.setData = function(d,e) { + this.setData = function(d,e, t) { if(typeof d != 'undefined') { data = {}; data = d; eras = e; + if(typeof t!='undefined') tags=t; build(); } else{ trace("NO DATA"); diff --git a/source/js/VMM.Timeline.js b/source/js/VMM.Timeline.js index ab8b430c1..7cee3e622 100755 --- a/source/js/VMM.Timeline.js +++ b/source/js/VMM.Timeline.js @@ -500,7 +500,7 @@ if(typeof VMM != 'undefined' && typeof VMM.Timeline == 'undefined') { // INITIALIZE COMPONENTS slider.init(_dates); - timenav.init(_dates, data.era); + timenav.init(_dates, data.era, data.tags); // RESIZE EVENT LISTENERS VMM.bindEvent(global, reSize, config.events.resize); @@ -687,4 +687,4 @@ if(typeof VMM != 'undefined' && typeof VMM.Timeline == 'undefined') { VMM.Timeline.Config = {}; -}; \ No newline at end of file +}; From 8a2b80456c4876fc0286f1e5840e5a1f82ed96fc Mon Sep 17 00:00:00 2001 From: "ronp@winter" Date: Thu, 26 Dec 2013 15:59:37 +0200 Subject: [PATCH 3/5] Adding control over row count, size, and ordering. 1. Fixed recursive merging of config object, allows setting properties under config.nav and below 2. Remove hard coded calculations of row size and count 3. Added support for pre-ordered rows via node in JSON --- README.markdown | 56 ++++++ examples/example_json.rows.html | 63 +++++++ examples/example_json.rows.json | 291 ++++++++++++++++++++++++++++++ source/js/Core/Core/VMM.Util.js | 8 +- source/js/VMM.Timeline.TimeNav.js | 20 +- source/js/VMM.Timeline.js | 3 +- 6 files changed, 432 insertions(+), 9 deletions(-) create mode 100644 examples/example_json.rows.html create mode 100644 examples/example_json.rows.json diff --git a/README.markdown b/README.markdown index da589f83a..f768e1e70 100644 --- a/README.markdown +++ b/README.markdown @@ -15,6 +15,7 @@ - [Map Style Types](#map-style-types) - [Font Options](#font-options) - [Font Combination Preview:](#font-combination-preview) + - [Nav Rows](#nav-rows) - [File Formats](#file-formats) - [JSON:](#json) - [JSONP :](#jsonp-) @@ -246,6 +247,61 @@ Due to recent changes to the Google Maps API, you need a [API Key](https://devel ####Font Combination Preview: ![Font Combination Preview](http://timeline.verite.co/gfx/font-options.png) +###Nav Rows +To enable finer control over the navigation slider, the following are +used: + +* `nav.height` describes total height of the nav-slider, including the ruler + (default 200) +* `nav.content_height` describes the height without the ruler. As the ruler is + generally 50px (unless you do some CSS changes) this is `nav.height`-50. so +default is 150px +* `nav.marker.height` describes marker/row height, default is 50px. Note that if you + have more than `nav.content_height`/`nav.marker.height` rows - then the row +height reduces to half. So in the default case you can fit 3 rows, and if more rows are +added, the height is reduced to 25px and 6 rows can fit. No fitting is done +beyond this, so if you have more rows, increase your nav sizes. + +Controlling rows is done by placing tags on `date` items (see [JSON:](#json) below). The tags label the rows and create affinity for events. +Also - by adding a `tags` section you can list the desired order of the tagged +rows. + +Finally - any change in size requires you to also handle the CSS. The common +case is just adding space for more rows, keeping the nicely formatted 50/25px +height. Here is an example of doing just that; There are also full files in git: +[example_json.rows.html](https://github.com/rpeleg1970/TimelineJS/blob/master/examples/example_json.rows.html) +and [example_json.rows.json](https://github.com/rpeleg1970/TimelineJS/blob/master/examples/example_json.rows.json) +```html + +
+ + + + + +``` + ## File Formats ### JSON: diff --git a/examples/example_json.rows.html b/examples/example_json.rows.html new file mode 100644 index 000000000..47518a77a --- /dev/null +++ b/examples/example_json.rows.html @@ -0,0 +1,63 @@ + + + + Timeline JS Example + + + + + + + + + + + +
+ + + + + + diff --git a/examples/example_json.rows.json b/examples/example_json.rows.json new file mode 100644 index 000000000..abd5e5789 --- /dev/null +++ b/examples/example_json.rows.json @@ -0,0 +1,291 @@ + +{ + "timeline": + { + "headline":"Sh*t People Say", + "type":"default", + "text":"People say stuff", + "startDate":"2012,1,26", + "tags": [ + "Behavior", + "Characters", + "Professions", + "Activities", + "Furry things", + "Other" + ], + "date": [ + { + "startDate":"2011,12,12", + "endDate":"2012,1,27", + "headline":"Vine", + "text":"

Vine Test

", + "tag": "Other", + "asset": + { + "media":"https://vine.co/v/b55LOA1dgJU", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,26", + "endDate":"2012,1,27", + "headline":"Sh*t Politicians Say", + "text":"

In true political fashion, his character rattles off common jargon heard from people running for office.

", + "tag": "Activities", + "asset": + { + "media":"http://youtu.be/u4XpeU9erbg", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,10", + "headline":"Sh*t Nobody Says", + "tag": "Other", + "text":"

Have you ever heard someone say “can I burn a copy of your Nickelback CD?” or “my Bazooka gum still has flavor!” Nobody says that.

", + "asset": + { + "media":"http://youtu.be/f-x8t0JOnVw", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,26", + "headline":"Sh*t Chicagoans Say", + "text":"", + "tag": "Characters", + "asset": + { + "media":"http://youtu.be/Ofy5gNkKGOo", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2011,12,12", + "headline":"Sh*t Girls Say", + "text":"", + "tag": "Behavior", + "asset": + { + "media":"http://youtu.be/u-yLGIH7W9Y", + "credit":"", + "caption":"Writers & Creators: Kyle Humphrey & Graydon Sheppard" + } + }, + { + "startDate":"2012,1,4", + "headline":"Sh*t Broke People Say", + "text":"", + "tag": "Characters", + "asset": + { + "media":"http://youtu.be/zyyalkHjSjo", + "credit":"", + "caption":"" + } + }, + + { + "startDate":"2012,1,4", + "headline":"Sh*t Silicon Valley Says", + "text":"", + "tag": "Characters", + "asset": + { + "media":"http://youtu.be/BR8zFANeBGQ", + "credit":"", + "caption":"written, filmed, and edited by Kate Imbach & Tom Conrad" + } + }, + { + "startDate":"2011,12,25", + "headline":"Sh*t Vegans Say", + "text":"", + "tag": "Characters", + "asset": + { + "media":"http://youtu.be/OmWFnd-p0Lw", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,23", + "headline":"Sh*t Graphic Designers Say", + "text":"", + "tag": "Professions", + "asset": + { + "media":"http://youtu.be/KsT3QTmsN5Q", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2011,12,30", + "headline":"Sh*t Wookiees Say", + "text":"", + "tag": "Furry things", + "asset": + { + "media":"http://youtu.be/vJpBCzzcSgA", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,17", + "headline":"Sh*t People Say About Sh*t People Say Videos", + "text":"", + "tag": "Other", + "asset": + { + "media":"http://youtu.be/c9ehQ7vO7c0", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,20", + "headline":"Sh*t Social Media Pros Say", + "text":"", + "tag": "Professions", + "asset": + { + "media":"http://youtu.be/eRQe-BT9g_U", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,11", + "headline":"Sh*t Old People Say About Computers", + "text":"", + "tag": "Characters", + "asset": + { + "media":"http://youtu.be/HRmc5uuoUzA", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,11", + "headline":"Sh*t College Freshmen Say", + "text":"", + "tag": "Behavior", + "asset": + { + "media":"http://youtu.be/rwozXzo0MZk", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2011,12,16", + "headline":"Sh*t Girls Say - Episode 2", + "text":"", + "tag": "Behavior", + "asset": + { + "media":"http://youtu.be/kbovd-e-hRg", + "credit":"", + "caption":"Writers & Creators: Kyle Humphrey & Graydon Sheppard" + } + }, + { + "startDate":"2011,12,24", + "headline":"Sh*t Girls Say - Episode 3 Featuring Juliette Lewis", + "text":"", + "tag": "Behavior", + "asset": + { + "media":"http://youtu.be/bDHUhT71JN8", + "credit":"", + "caption":"Writers & Creators: Kyle Humphrey & Graydon Sheppard" + } + }, + { + "startDate":"2012,1,27", + "headline":"Sh*t Web Designers Say", + "text":"", + "tag": "Professions", + "asset": + { + "media":"http://youtu.be/MEOb_meSHhQ", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,12", + "headline":"Sh*t Hipsters Say", + "text":"No meme is complete without a bit of hipster-bashing.", + "tag": "Characters", + "asset": + { + "media":"http://youtu.be/FUhrSVyu0Kw", + "credit":"", + "caption":"Written, Directed, Conceptualized and Performed by Carrie Valentine and Jessica Katz" + } + }, + { + "startDate":"2012,1,6", + "headline":"Sh*t Cats Say", + "text":"No meme is complete without cats. This had to happen, obviously.", + "tag": "Furry things", + "asset": + { + "media":"http://youtu.be/MUX58Vi-YLg", + "credit":"", + "caption":"" + } + }, + { + "startDate":"2012,1,21", + "headline":"Sh*t Cyclists Say", + "tag": "Activities", + "text":"", + "asset": + { + "media":"http://youtu.be/GMCkuqL9IcM", + "credit":"", + "caption":"Video script, production, and editing by Allen Krughoff of Hardcastle Photography" + } + }, + { + "startDate":"2011,12,30", + "headline":"Sh*t Yogis Say", + "text":"", + "tag": "Professions", + "asset": + { + "media":"http://youtu.be/IMC1_RH_b3k", + "credit":"", + "caption":"" + } + }, + + + + + { + "startDate":"2012,1,18", + "headline":"Sh*t New Yorkers Say", + "text":"", + "tag": "Characters", + "asset": + { + "media":"http://youtu.be/yRvJylbSg7o", + "credit":"", + "caption":"Directed and Edited by Matt Mayer, Produced by Seth Keim, Written by Eliot Glazer. Featuring Eliot and Ilana Glazer, who are siblings, not married." + } + } + ] + } +} diff --git a/source/js/Core/Core/VMM.Util.js b/source/js/Core/Core/VMM.Util.js index c0610e535..2c12948d0 100644 --- a/source/js/Core/Core/VMM.Util.js +++ b/source/js/Core/Core/VMM.Util.js @@ -31,7 +31,11 @@ if(typeof VMM != 'undefined' && typeof VMM.Util == 'undefined') { var x; for (x in config_to_merge) { if (Object.prototype.hasOwnProperty.call(config_to_merge, x)) { - config_main[x] = config_to_merge[x]; + if(typeof(config_main[x])=="object") { + VMM.Util.mergeConfig(config_main[x],config_to_merge[x]); + } else { + config_main[x] = config_to_merge[x]; + } } } return config_main; @@ -475,4 +479,4 @@ if(typeof VMM != 'undefined' && typeof VMM.Util == 'undefined') { } }).init(); -} \ No newline at end of file +} diff --git a/source/js/VMM.Timeline.TimeNav.js b/source/js/VMM.Timeline.TimeNav.js index 19ff7331e..0b6a89ea2 100644 --- a/source/js/VMM.Timeline.TimeNav.js +++ b/source/js/VMM.Timeline.TimeNav.js @@ -121,12 +121,18 @@ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefin /* ADD to Config ================================================== */ - row_height = config.nav.marker.height/2; + row_height = config.nav.marker.height / 2; + row_count = config.nav.content_height / row_height; config.nav.rows = { - full: [1, row_height*2, row_height*4], - half: [1, row_height, row_height*2, row_height*3, row_height*4, row_height*5], + full: [1, row_height*2], + half: [1, row_height, row_height*2, row_height*3], current: [] } + for(var i=4; i 3) { + var threashold = config.nav.content_height / config.nav.marker.height; + if(isNaN(threashold)) threashold = 3; + if (tags.length > threashold) { config.nav.rows.current = config.nav.rows.half; } else { config.nav.rows.current = config.nav.rows.full; @@ -1559,7 +1567,7 @@ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefin if (k < config.nav.rows.current.length) { var tag_element = VMM.appendAndGetElement($timebackground, "
", "timenav-tag"); VMM.Lib.addClass(tag_element, "timenav-tag-row-" + (k+1)); - if (tags.length > 3) { + if (tags.length > threashold) { VMM.Lib.addClass(tag_element, "timenav-tag-size-half"); } else { VMM.Lib.addClass(tag_element, "timenav-tag-size-full"); @@ -1570,7 +1578,7 @@ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefin } // RESIZE FLAGS IF NEEDED - if (tags.length > 3) { + if (tags.length > threashold) { for(l = 0; l < markers.length; l++) { VMM.Lib.addClass(markers[l].flag, "flag-small"); markers[l].full = false; diff --git a/source/js/VMM.Timeline.js b/source/js/VMM.Timeline.js index 7cee3e622..bcf388f2f 100755 --- a/source/js/VMM.Timeline.js +++ b/source/js/VMM.Timeline.js @@ -109,6 +109,7 @@ if(typeof VMM != 'undefined' && typeof VMM.Timeline == 'undefined') { rows: [1, 1, 1], width: 960, height: 200, + content_height: 150, marker: { width: 150, height: 50 @@ -188,7 +189,7 @@ if(typeof VMM != 'undefined' && typeof VMM.Timeline == 'undefined') { } config.nav.width = config.width; - config.nav.height = 200; + // config.nav.height = 200; This comes from the default merged config config.feature.width = config.width; config.feature.height = config.height - config.nav.height; config.nav.zoom.adjust = parseInt(config.start_zoom_adjust, 10); From 2f5fdc1900b9a685984a862878fd959655c8a147 Mon Sep 17 00:00:00 2001 From: "ronp@winter" Date: Thu, 26 Dec 2013 16:05:04 +0200 Subject: [PATCH 4/5] typos and broken links --- README.markdown | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.markdown b/README.markdown index f768e1e70..2e0da4531 100644 --- a/README.markdown +++ b/README.markdown @@ -252,9 +252,9 @@ To enable finer control over the navigation slider, the following are used: * `nav.height` describes total height of the nav-slider, including the ruler - (default 200) + (default 200px) * `nav.content_height` describes the height without the ruler. As the ruler is - generally 50px (unless you do some CSS changes) this is `nav.height`-50. so + generally 50px (unless you do some CSS changes) this is `nav.height-50`, so default is 150px * `nav.marker.height` describes marker/row height, default is 50px. Note that if you have more than `nav.content_height`/`nav.marker.height` rows - then the row @@ -269,8 +269,8 @@ rows. Finally - any change in size requires you to also handle the CSS. The common case is just adding space for more rows, keeping the nicely formatted 50/25px height. Here is an example of doing just that; There are also full files in git: -[example_json.rows.html](https://github.com/rpeleg1970/TimelineJS/blob/master/examples/example_json.rows.html) -and [example_json.rows.json](https://github.com/rpeleg1970/TimelineJS/blob/master/examples/example_json.rows.json) +[example_json.rows.html](https://github.com/rpeleg1970/TimelineJS/blob/swimlanes/examples/example_json.rows.html) +and [example_json.rows.json](https://github.com/rpeleg1970/TimelineJS/blob/swimlanes/examples/example_json.rows.json) ```html
@@ -311,9 +311,9 @@ JSON is the native data format for TimelineJS. Remember, JSON is picky. A misplaced comma or quotation mark can prevent the timeline from loading properly. -Note that optional tags on events (dates) puts them in an annotated `swimlane` +Note that optional tags on events (dates) puts them in an annotated row in the TimeNav. Adding the `tags` list to the JSON file allows you to control -the order of these swimlanes. +the order of these rows. Here is the full model: ```javascript From 9d7d75aa00b0b4c8c71a2025b9c976eac2bcf708 Mon Sep 17 00:00:00 2001 From: "ronp@winter" Date: Tue, 31 Dec 2013 09:14:12 +0200 Subject: [PATCH 5/5] fixed: + JSON timeout was 3 seconds. In some cases it casued the timeline to get stuck on load. Increased to 10 secs. + Fixed hard-coded position of event-line-indicator (blue line on timeline ruler, indicates start->end life of event) --- source/js/Core/Core/VMM.Library.js | 2 +- source/js/VMM.Timeline.TimeNav.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/js/Core/Core/VMM.Library.js b/source/js/Core/Core/VMM.Library.js index 0b4935aa5..8dc2d54db 100644 --- a/source/js/Core/Core/VMM.Library.js +++ b/source/js/Core/Core/VMM.Library.js @@ -127,7 +127,7 @@ if(typeof VMM != 'undefined') { VMM.getJSON = function(url, data, callback) { if( typeof( jQuery ) != 'undefined' ){ jQuery.ajaxSetup({ - timeout: 3000 + timeout: 10000 }); /* CHECK FOR IE ================================================== */ diff --git a/source/js/VMM.Timeline.TimeNav.js b/source/js/VMM.Timeline.TimeNav.js index 0b6a89ea2..7ce987fe6 100644 --- a/source/js/VMM.Timeline.TimeNav.js +++ b/source/js/VMM.Timeline.TimeNav.js @@ -714,7 +714,7 @@ if(typeof VMM.Timeline != 'undefined' && typeof VMM.Timeline.TimeNav == 'undefin pos_offset = -2, row_depth = 0, row_depth_sub = 0, - line_last_height_pos = 150, + line_last_height_pos = config.nav.content_height, line_height = 6, cur_mark = 0, in_view_margin = config.width,