comparison geotemco/js/PieChart/PieChart.js @ 0:b12c99b7c3f0

commit for previous development
author Zoe Hong <zhong@mpiwg-berlin.mpg.de>
date Mon, 19 Jan 2015 17:13:49 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:b12c99b7c3f0
1 /*
2 * PieChart.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 PieChart
24 * Implementation for a PieChart
25 * @author Sebastian Kruse (skruse@mpiwg-berlin.mpg.de)
26 *
27 * @param {HTML object} parent div to append the PieChart
28 */
29 function PieChart(parent, watchedDataset, watchedColumn, selectionFunction) {
30
31 if ((typeof selectionFunction !== "undefined") &&
32 (typeof selectionFunction.type !== "undefined") &&
33 (typeof selectionFunction.categories !== "undefined")){
34 this.type = selectionFunction.type;
35 this.categories = selectionFunction.categories;
36 }
37 this.pieChart = this;
38 this.pieChartDiv;
39 this.preHighlightObjects;
40 this.highlightedLabel;
41
42 this.informationDIV;
43 this.pieChartLabel;
44
45 this.parent = parent;
46 this.options = parent.options;
47
48 this.watchedDatasetObject;
49 this.watchedDataset = parseInt(watchedDataset);
50 this.watchColumn = watchedColumn;
51 if (typeof selectionFunction !== "undefined")
52 this.selectionFunction = selectionFunction;
53 else
54 //default selectionFunction returns value (creates "distinct" piechart)
55 this.selectionFunction = function(columnData){return columnData;};
56 }
57
58 PieChart.prototype = {
59
60 remove : function() {
61 for (var i = 0; i < this.parent.pieCharts.length; i++){
62 if (this.parent.pieCharts[i] === this)
63 this.parent.pieCharts[i] = null;
64 }
65 $(this.pieChartDiv).remove();
66 $(this.informationDIV).remove();
67 this.parent.redrawPieCharts();
68 },
69
70 refreshLabel : function(){
71 $(this.pieChartLabel).empty();
72 $(this.pieChartLabel).append(this.watchedDatasetObject.label + " - " + this.watchColumn);
73
74 var c = GeoTemConfig.getColor(this.watchedDataset);
75 $(this.pieChartLabel).css("color","rgb("+c.r1+","+c.g1+","+c.b1+")");
76 },
77
78 initialize : function() {
79 var pieChart = this;
80
81 if (typeof this.pieChartDiv === "undefined"){
82 this.informationDIV = document.createElement("div");
83 this.pieChartLabel = $("<span></span>");
84 $(this.informationDIV).append(this.pieChartLabel);
85 this.refreshLabel();
86
87 var removeButton = document.createElement("button");
88 $(this.informationDIV).append(removeButton);
89 $(removeButton).text("remove");
90 $(removeButton).click(function(){
91 pieChart.remove();
92 });
93
94 //only allow editing if it is a "manually" created piechart
95 //automatic (with a selection function) ones, can lead to numerous problems,
96 //e.g. too many categories or numeral categories threated as text ones
97 if ((typeof pieChart.type !== "undefined")&&
98 (typeof pieChart.categories !== "undefined")){
99 var editButton = document.createElement("button");
100 $(this.informationDIV).append(editButton);
101 $(editButton).text("edit");
102 $(editButton).click(function(){
103 var chooser = new PieChartCategoryChooser(
104 pieChart.parent,
105 pieChart.parent.options,
106 pieChart.watchedDataset,
107 pieChart.watchColumn,
108 pieChart.type,
109 pieChart.categories);
110 });
111
112 //add save button
113 if (pieChart.options.allowLocalStorage){
114 var saveButton = document.createElement("button");
115 $(this.informationDIV).append(saveButton);
116 $(saveButton).text("save");
117 $(saveButton).click(function(){
118 $( "<div>" +
119 "pie chart name : " +
120 "<input type='text' size=30 id='saveName' class='ui-widget-content ui-corner-all'></input>" +
121 "</div>").dialog({
122 width:'auto',
123 buttons: [
124 {
125 text: "save",
126 click: function(){
127 var saveName = $("#saveName").val();
128 var saveObject = new Object();
129 saveObject.type = pieChart.type;
130 saveObject.categories = pieChart.categories;
131 saveObject.columnName = pieChart.watchColumn;
132 //save to LocalStorage
133 $.remember({
134 name:pieChart.options.localStoragePrefix+saveName,
135 value:saveObject,
136 json:true
137 });
138 $(this).dialog( "close" );
139 }
140 }
141 ]
142 });
143
144 //set value to default (column name)
145 $("#saveName").val(pieChart.watchColumn);
146 //TODO: z-index has to be set, as the "tool-bars" of map (.ddbToolbar in style.css)
147 //also have a z-index of 10000. z-index should be removed from all elements.
148 $(".ui-dialog").css("z-index",10005);
149 });
150 }
151 }
152
153 $(this.parent.gui.pieChartsDiv).append(this.informationDIV);
154 this.pieChartDiv = document.createElement("div");
155 $(this.parent.gui.pieChartsDiv).append(this.pieChartDiv);
156
157 $(this.pieChartDiv).unbind();
158 $(this.pieChartDiv).bind("plothover", function (event, pos, item) {
159 var highlightedLabel;
160
161 if (item) {
162 highlightedLabel = item.series.label;
163 }
164 if (highlightedLabel !== pieChart.highlightedLabel){
165 pieChart.highlightedLabel = highlightedLabel;
166 pieChart.triggerHighlight(highlightedLabel);
167 }
168 });
169
170 $(this.pieChartDiv).bind("plotclick", function (event, pos, item) {
171 if (item) {
172 //item.series.label contains the column element
173 pieChart.triggerSelection(item.series.label);
174 } else {
175 pieChart.triggerSelection();
176 }
177 });
178 }
179 },
180
181 //check if dataset is still there
182 checkForDataSet : function() {
183 var datasets = this.parent.datasets;
184 if ((typeof datasets !== "undefined") && (typeof this.watchedDatasetObject !== "undefined")){
185 //check if our data went missing
186 for (var i = 0; i < datasets.length; i++){
187 if (datasets[i] === this.watchedDatasetObject){
188 //if dataset "before" this one was removed, the index changes
189 if (this.watchedDataset !== i){
190 //change color to the new one (changes with index!)
191 this.watchedDataset = i;
192 this.refreshLabel();
193 }
194 return true;
195 }
196 }
197 }
198 return false;
199 },
200
201 initPieChart : function(dataSets) {
202 // get dataset object (could not be there on startup, e.g. piechart defined before load completes)
203 if (typeof this.watchedDatasetObject === "undefined")
204 this.watchedDatasetObject = this.parent.datasets[this.watchedDataset];
205
206 this.initialize();
207
208 // if our dataset went missing, remove this piechart
209 if (!this.checkForDataSet()){
210 this.remove();
211 return;
212 }
213
214 var objects = [];
215 for (var i = 0; i < dataSets.length; i++)
216 objects.push([]);
217 objects[this.watchedDataset] = dataSets[this.watchedDataset].objects;
218
219 this.preHighlightObjects = objects;
220 this.redrawPieChart(objects);
221 },
222
223 redrawPieChart : function(objects) {
224
225 if (typeof objects === "undefined")
226 objects = this.preHighlightObjects;
227
228 if (this.checkForDataSet(objects)){
229 var pieChart = this;
230 if (objects[this.watchedDataset].length === 0)
231 objects = this.preHighlightObjects;
232
233 var calculateSlices = function(dataObjects){
234 var chartDataCounter = new Object;
235
236 $(dataObjects).each(function(){
237 var columnData = pieChart.parent.getElementData(this, pieChart.watchColumn, pieChart.selectionFunction);
238
239 //disregard empty cells
240 if ( (typeof columnData === "undefined") || (columnData == "") )
241 return;
242
243 var weight = this.weight;
244
245 if (typeof chartDataCounter[columnData] === "undefined")
246 chartDataCounter[columnData] = weight;
247 else
248 chartDataCounter[columnData] += weight;
249 });
250
251 var chartData = [];
252 $.each(chartDataCounter, function(name,val){
253 //get rgb-color (24bit = 6 hex digits) from hash
254 var color = '#'+hex_md5(name).substr(0,6);
255 chartData.push({label:name,data:val,color:color});
256 });
257
258 //sort by count (occurances of category)
259 var sortByVal = function(a,b){
260 return (b.data-a.data);
261 };
262 chartData.sort(sortByVal);
263
264 return chartData;
265 };
266
267 var chartData = calculateSlices(objects[this.watchedDataset]);
268
269 if (chartData.length>0){
270 $(this.pieChartDiv).empty();
271
272 //calculate height (flot NEEDS a height)
273 var parentHeight = $(this.parent.gui.pieChartsDiv).outerHeight(true) - $(this.parent.gui.columnSelectorDiv).outerHeight(true);
274 var pieChartCount = 0;
275 $(this.parent.pieCharts).each(function(){
276 if (this instanceof PieChart)
277 pieChartCount++;
278 });
279 var height = (parentHeight/pieChartCount) - $(this.informationDIV).outerHeight(true);
280 if (pieChart.options.restrictPieChartSize !== false)
281 height = Math.min(height, $(window).height() * pieChart.options.restrictPieChartSize);
282 $(this.pieChartDiv).height(height);
283
284 $.plot($(this.pieChartDiv), chartData,
285 {
286 series: {
287 // Make this a pie chart.
288 pie: {
289 show:true
290 }
291 },
292 legend: { show:true, position: 'se' },
293 grid: {
294 hoverable: true,
295 clickable: true
296 },
297 tooltip: true,
298 tooltipOpts: {
299 content: "%s %p.1%"
300 }
301 }
302 );
303 }
304 }
305 },
306
307 triggerHighlight : function(columnElement) {
308 var highlightedObjects = [];
309 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
310 highlightedObjects.push([]);
311
312 if (this.watchedDataset >= 0)
313 highlightedObjects[this.watchedDataset] =
314 this.parent.getElementsByValue(columnElement, this.watchedDataset, this.watchColumn, this.selectionFunction);
315 else
316 highlightedObjects[this.watchedDataset] = [];
317
318 this.parent.core.triggerHighlight(highlightedObjects);
319
320 var pieChart = this;
321 $(this.parent.pieCharts).each(function(){
322 if (this instanceof PieChart && (this !== pieChart)){
323 if (this.watchedDataset === pieChart.watchedDataset)
324 this.redrawPieChart(highlightedObjects);
325 }
326 });
327 },
328
329 triggerSelection : function(columnElement) {
330 var selectedObjects = [];
331 for (var i = 0; i < GeoTemConfig.datasets.length; i++)
332 selectedObjects.push([]);
333
334 var selection;
335 if (typeof columnElement !== "undefined"){
336 selectedObjects[this.watchedDataset] =
337 this.parent.getElementsByValue(columnElement, this.watchedDataset, this.watchColumn, this.selectionFunction);
338 selection = new Selection(selectedObjects, this);
339 } else {
340 selection = new Selection(selectedObjects);
341 }
342
343 this.parent.core.triggerSelection(selection);
344
345 if (!selection.valid()){
346 selection.loadAllObjects();
347 //"undo" selection (click next to piechart)
348 //so also redraw this dataset
349 this.preHighlightObjects = selection.objects;
350 this.redrawPieChart(selection.objects);
351 }
352
353 var pieChart = this;
354 $(this.parent.pieCharts).each(function(){
355 if (this instanceof PieChart && (this !== pieChart)){
356 if (this.watchedDataset === pieChart.watchedDataset){
357 this.preHighlightObjects = selection.objects;
358 this.redrawPieChart(selection.objects);
359 }
360 }
361 });
362 },
363
364 deselection : function() {
365 },
366
367 filtering : function() {
368 },
369
370 inverseFiltering : function() {
371 },
372
373 triggerRefining : function() {
374 },
375
376 reset : function() {
377 },
378
379 show : function() {
380 },
381
382 hide : function() {
383 }
384 };