0
|
1 /*
|
|
2 * FuzzyTimelineRangePiechart.js
|
|
3 *
|
|
4 * Copyright (c) 2013, Sebastian Kruse. All rights reserved.
|
|
5 *
|
|
6 * This library is free software; you can redistribute it and/or
|
|
7 * modify it under the terms of the GNU Lesser General Public
|
|
8 * License as published by the Free Software Foundation; either
|
|
9 * version 3 of the License, or (at your option) any later version.
|
|
10 *
|
|
11 * This library is distributed in the hope that it will be useful,
|
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
14 * Lesser General Public License for more details.
|
|
15 *
|
|
16 * You should have received a copy of the GNU Lesser General Public
|
|
17 * License along with this library; if not, write to the Free Software
|
|
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
19 * MA 02110-1301 USA
|
|
20 */
|
|
21
|
|
22 /**
|
|
23 * @class FuzzyTimelineRangePiechart
|
|
24 * Implementation for a fuzzy time-ranges pie chart
|
|
25 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
|
|
26 *
|
|
27 * @param {HTML object} parent div to append the FuzzyTimeline
|
|
28 */
|
|
29 function FuzzyTimelineRangePiechart(parent,div) {
|
|
30
|
|
31 this.fuzzyTimeline = this;
|
|
32
|
|
33 this.parent = parent;
|
|
34 this.options = parent.options;
|
|
35
|
|
36 this.div = div;
|
|
37
|
|
38 this.selected = [];
|
|
39
|
|
40 this.maxSlices = 10;
|
|
41 }
|
|
42
|
|
43 FuzzyTimelineRangePiechart.prototype = {
|
|
44
|
|
45 initialize : function(datasets) {
|
|
46 var piechart = this;
|
|
47 if (piechart.parent.showRangePiechart){
|
|
48 piechart.datasets = datasets;
|
|
49 piechart.drawPieChart(piechart.datasets);
|
|
50 }
|
|
51 },
|
|
52
|
|
53 drawPieChart : function(datasets){
|
|
54 var piechart = this;
|
|
55 //build hashmap of spans (span length -> objects[])
|
|
56 var spans = [];
|
|
57 var index = 0;
|
|
58 $(datasets).each(function(){
|
|
59 var objects = this;
|
|
60 //check whether we got "real" dataset or just a set of DataObjects
|
|
61 if (typeof objects.objects !== "undefined")
|
|
62 objects = objects.objects;
|
|
63 $(objects).each(function(){
|
|
64 var dataObject = this;
|
|
65 var span;
|
|
66 if (dataObject.isTemporal){
|
|
67 span = SimileAjax.DateTime.MILLISECOND;
|
|
68 } else if (dataObject.isFuzzyTemporal){
|
|
69 span = dataObject.TimeSpanGranularity;
|
|
70 }
|
|
71
|
|
72 if (typeof span === "undefined")
|
|
73 return;
|
|
74
|
|
75 var found = false;
|
|
76 $(spans).each(function(){
|
|
77 if (this.span === span){
|
|
78 this.objects[index].push(dataObject);
|
|
79 found = true;
|
|
80 return false;
|
|
81 }
|
|
82 });
|
|
83 if (found === false){
|
|
84 var newObjectSet = [];
|
|
85 for (var i = 0; i < piechart.datasets.length; i++)
|
|
86 newObjectSet.push([]);
|
|
87 newObjectSet[index].push(dataObject);
|
|
88 spans.push({span:span,objects:newObjectSet});
|
|
89 }
|
|
90 });
|
|
91 index++;
|
|
92 });
|
|
93
|
|
94 //TODO: join elements of span array to keep below certain threshold
|
|
95
|
|
96 //sort array by span length
|
|
97 spans.sort(function(a,b){
|
|
98 return(a.span-b.span);
|
|
99 });
|
|
100
|
|
101 //create chart data
|
|
102 var chartData = [];
|
|
103 $(spans).each(function(){
|
|
104 var spanElem = this;
|
|
105 $(spanElem.objects).each(function(){
|
|
106 var label = "unknown";
|
|
107
|
|
108 if (spanElem.span === SimileAjax.DateTime.MILLENNIUM){
|
|
109 label = "millenia";
|
|
110 } else if (spanElem.span === SimileAjax.DateTime.DECADE){
|
|
111 label = "decades";
|
|
112 } else if (spanElem.span === SimileAjax.DateTime.CENTURY){
|
|
113 label = "centuries";
|
|
114 } else if (spanElem.span === SimileAjax.DateTime.YEAR){
|
|
115 label = "years";
|
|
116 } else if (spanElem.span === SimileAjax.DateTime.MONTH){
|
|
117 label = "months";
|
|
118 } else if (spanElem.span === SimileAjax.DateTime.DAY){
|
|
119 label = "days";
|
|
120 } else if (spanElem.span === SimileAjax.DateTime.HOUR){
|
|
121 label = "hours";
|
|
122 } else if (spanElem.span === SimileAjax.DateTime.MINUTE){
|
|
123 label = "minutes";
|
|
124 } else if (spanElem.span === SimileAjax.DateTime.SECOND){
|
|
125 label = "seconds";
|
|
126 } else if (spanElem.span === SimileAjax.DateTime.MILLISECOND){
|
|
127 label = "milliseconds";
|
|
128 }
|
|
129
|
|
130 chartData.push({label:label,data:this.length});
|
|
131 });
|
|
132 });
|
|
133
|
|
134 $(piechart.div).unbind("plotclick");
|
|
135 $(piechart.div).unbind("plothover");
|
|
136 $(piechart.div).empty();
|
|
137 if (spans.length === 0){
|
|
138 //TODO: language specific message
|
|
139 $(piechart.div).append("empty selection");
|
|
140 } else {
|
|
141 $.plot($(piechart.div), chartData,
|
|
142 {
|
|
143 series: {
|
|
144 // Make this a pie chart.
|
|
145 pie: {
|
|
146 show:true
|
|
147 }
|
|
148 },
|
|
149 legend: { show:false},
|
|
150 grid: {
|
|
151 hoverable: true,
|
|
152 clickable: true
|
|
153 },
|
|
154 tooltip: true,
|
|
155 }
|
|
156 );
|
|
157
|
|
158 var lastHighlighted;
|
|
159 var hoverFunction = function (event, pos, item) {
|
|
160 if (item) {
|
|
161 var highlightedSpan = Math.ceil(item.seriesIndex/piechart.datasets.length);
|
|
162 if (lastHighlighted !== highlightedSpan){
|
|
163 var highlightedObjects = [];
|
|
164 for(;highlightedSpan>=0;highlightedSpan--){
|
|
165 highlightedObjects = GeoTemConfig.mergeObjects(highlightedObjects,spans[highlightedSpan].objects);
|
|
166 }
|
|
167 lastHighlighted = highlightedSpan;
|
|
168 }
|
|
169 piechart.triggerHighlight(highlightedObjects);
|
|
170 } else {
|
|
171 piechart.triggerHighlight([]);
|
|
172 }
|
|
173 };
|
|
174 $(piechart.div).bind("plothover", hoverFunction);
|
|
175
|
|
176 $(piechart.div).bind("plotclick", function (event, pos, item) {
|
|
177 $(piechart.div).unbind("plothover");
|
|
178 if (item){
|
|
179 var selectedSpan = Math.ceil(item.seriesIndex/piechart.datasets.length);
|
|
180 var selectedObjects = [];
|
|
181 for(;selectedSpan>=0;selectedSpan--){
|
|
182 selectedObjects = GeoTemConfig.mergeObjects(selectedObjects,spans[selectedSpan].objects);
|
|
183 }
|
|
184 piechart.triggerSelection(selectedObjects);
|
|
185 } else {
|
|
186 //if it was a click outside of the pie-chart, enable highlight events
|
|
187 $(piechart.div).bind("plothover", hoverFunction);
|
|
188 //return to old state
|
|
189 piechart.triggerSelection(piechart.selected);
|
|
190 //and redraw piechart
|
|
191 piechart.highlightChanged([]);
|
|
192 }
|
|
193 });
|
|
194 }
|
|
195 },
|
|
196
|
|
197 highlightChanged : function(objects) {
|
|
198 var piechart = this;
|
|
199 if (piechart.parent.showRangePiechart){
|
|
200 //check if this is an empty highlight
|
|
201 var emptyHighlight = true;
|
|
202 $(objects).each(function(){
|
|
203 if ((this instanceof Array) && (this.length > 0)){
|
|
204 emptyHighlight = false;
|
|
205 return false;
|
|
206 }
|
|
207 });
|
|
208
|
|
209 if (emptyHighlight === false)
|
|
210 piechart.drawPieChart(GeoTemConfig.mergeObjects(piechart.selected, objects));
|
|
211 else{
|
|
212 //return to selection (or all objects, if no selection is active)
|
|
213 if (piechart.selected.length > 0)
|
|
214 piechart.drawPieChart(piechart.selected);
|
|
215 else
|
|
216 piechart.drawPieChart(piechart.datasets);
|
|
217 }
|
|
218 }
|
|
219 },
|
|
220
|
|
221 selectionChanged : function(selection) {
|
|
222 var piechart = this;
|
|
223 if (piechart.parent.showRangePiechart){
|
|
224 if( !GeoTemConfig.selectionEvents ){
|
|
225 return;
|
|
226 }
|
|
227 piechart.selected = selection;
|
|
228 piechart.highlightChanged([]);
|
|
229 }
|
|
230 },
|
|
231
|
|
232 triggerHighlight : function(highlightedObjects) {
|
|
233 this.parent.triggerHighlight(highlightedObjects);
|
|
234 },
|
|
235
|
|
236 triggerSelection : function(selectedObjects) {
|
|
237 this.parent.triggerSelection(selectedObjects);
|
|
238 },
|
|
239
|
|
240 deselection : function() {
|
|
241 },
|
|
242
|
|
243 filtering : function() {
|
|
244 },
|
|
245
|
|
246 inverseFiltering : function() {
|
|
247 },
|
|
248
|
|
249 triggerRefining : function() {
|
|
250 },
|
|
251
|
|
252 reset : function() {
|
|
253 },
|
|
254
|
|
255 show : function() {
|
|
256 },
|
|
257
|
|
258 hide : function() {
|
|
259 }
|
|
260 };
|