comparison hexagram-6ae12361157c/hexagram/tools.js @ 0:1407e3634bcf draft default tip

Uploaded r11 from test tool shed.
author adam-novak
date Tue, 22 Oct 2013 14:17:59 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1407e3634bcf
1 // tools.js: Code to run all the tools in the menu bar.
2 // References globals in hexagram.js to actually do the tools' work.
3
4 // To add a tool:
5 // * Make a $(function() {...}); block to hold your code.
6 // * Add a tool with add_tool with your tool code as the callback.
7 // * Add at least one tool listener with add_tool_listener. Give it cleanup code
8 // if necessary to remove temporary UI elements.
9 // * Make sure to set selected_tool to undefined when your tool's normal
10 // workflow completes, so that the infowindow can use click events again.
11 // (it got set to your tool's name by the code prepended to your callback).
12
13 $(function() {
14 // Set up the add text control
15 add_tool("add-text", "Add Text...", function() {
16
17 // We'll prompt the user for some text, and then put a label where they
18 // next click.
19
20 var text = prompt("Enter some text, and click anywhere on the " +
21 "visualization to place it there", "Label Text");
22
23 if(!text) {
24 // They don't want to put a label
25 selected_tool = undefined;
26 return;
27 }
28
29 // Add a tool listenerr that places the label. It fires on a click
30 // anywhere on anything on the map, including the background. We keep a
31 // handle to it so we can remove it when it fires, ensuring we get just
32 // one label. See http://stackoverflow.com/a/1544185
33 var handle = add_tool_listener("click", function(event) {
34
35 // Make a new MapLabel at the click position
36 // See http://bit.ly/18MbLhR (the MapLabel library example page)
37 var map_label = new MapLabel({
38 text: text,
39 position: event.latLng,
40 map: googlemap,
41 fontSize: 10,
42 align: "left"
43 });
44
45 // Subscribe tool listeners to the label
46 subscribe_tool_listeners(map_label);
47
48 // Don't trigger again
49 remove_tool_listener(handle);
50 }, function() {
51 // Cleanup: de-select ourselves.
52 selected_tool = undefined;
53 });
54 });
55 });
56
57 $(function() {
58 // Set up the selection tool
59 add_tool("select", "Select", function() {
60
61 // Turn on a crosshair cursor
62 googlemap.setOptions({
63 draggableCursor:"crosshair"
64 });
65
66 // Add a listener to start the selection where the user clicks
67 var start_handle = add_tool_listener("click",
68 function(event) {
69
70 // Don't trigger again
71 remove_tool_listener(start_handle);
72
73 // Turn on a crosshair cursor again
74 googlemap.setOptions({
75 draggableCursor:"crosshair"
76 });
77
78 // Store the start of the selection
79 var selection_start = event.latLng;
80
81 print("Selection started at " + selection_start);
82
83 // Make a rectangle for the selection
84 var rectangle = new google.maps.Rectangle({
85 fillColor: "#FFFFFF",
86 strokeColor: "#FFFFFF",
87 strokeWeight: 2,
88 strokeOpacity: 1.0,
89 fillOpacity: 0.5,
90 // Don't give us a clickable cursor, or take mouse events.
91 clickable: false,
92 map: googlemap,
93 bounds: new google.maps.LatLngBounds(selection_start,
94 selection_start)
95 });
96
97 // This holds a selection preview event handler that should happen
98 // when we mouse over the map or the rectangle.
99 var preview = function(event) {
100
101 // Store the end of the selection (provisionally)
102 var selection_end = event.latLng;
103
104
105 if(selection_end.lng() < selection_start.lng()) {
106 // The user has selected a backwards rectangle, which wraps
107 // across the place where the globe is cut. None of our
108 // selections ever need to do this.
109
110 // Make the rectangle backwards
111 rectangle.setBounds(new google.maps.LatLngBounds(
112 selection_end, selection_start));
113
114 } else {
115 // Make the rectangle forwards
116 rectangle.setBounds(new google.maps.LatLngBounds(
117 selection_start, selection_end));
118 }
119 }
120
121 // This holds a cleanup function to get rid of the rectangle when
122 // the resizing listener goes away.
123 var preview_cleanup = function() {
124 // Remove the rectangle
125 rectangle.setMap(undefined);
126
127 // Remove the crosshair cursor
128 googlemap.setOptions({
129 draggableCursor: undefined
130 });
131 };
132
133 // Add a mouse move listener for interactivity
134 // Works over the map, hexes, or the rectangle.
135 var move_handle = add_tool_listener("mousemove", preview,
136 preview_cleanup);
137
138 // We need a listener to finish the selection
139 var finish = function(event) {
140 // Don't trigger again
141 remove_tool_listener(stop_handle);
142
143 // Also stop the dynamic updates. This removes the rectangle.
144 remove_tool_listener(move_handle);
145
146 // Store the end of the selection
147 var selection_end = event.latLng;
148
149 print("Selection ended at " + selection_end);
150
151 // Select the rectangle by arbitrary corners.
152 select_rectangle(selection_start, selection_end);
153 };
154
155 // Attach the listener.
156 // The listener can still use its own handle because variable
157 // references are resolved at runtime.
158 var stop_handle = add_tool_listener("click", finish, function() {
159 // Cleanup: say this tool is no longer selected
160 selected_tool = undefined;
161 });
162
163 }, function() {
164 // Remove the crosshair cursor
165 googlemap.setOptions({
166 draggableCursor: undefined
167 });
168 });
169 });
170 });
171
172 // A tool for importing a list of hexes as a selection
173 $(function() {
174 add_tool("import", "Import...", function() {
175 // Make the import form
176 var import_form = $("<form/>").attr("title",
177 "Import List As Selection");
178
179 import_form.append($("<div/>").text("Input names, one per line:"));
180
181 // A big text box
182 var text_area = $("<textarea/>").addClass("import");
183 import_form.append(text_area);
184
185 import_form.append($("<div/>").text(
186 "Open a file:"));
187
188 // This holds a file form element
189 var file_picker = $("<input/>").attr("type", "file").addClass("import");
190
191 import_form.append(file_picker);
192
193 file_picker.change(function(event) {
194 // When a file is selected, read it in and populate the text box.
195
196 // What file do we really want to read?
197 var file = event.target.files[0];
198
199 // Make a FileReader to read the file
200 var reader = new FileReader();
201
202 reader.onload = function(read_event) {
203 // When we read with readAsText, we get a string. Just stuff it
204 // in the text box for the user to see.
205 text_area.text(reader.result);
206 };
207
208 // Read the file, and, when it comes in, stick it in the textbox.
209 reader.readAsText(file);
210 });
211
212 import_form.dialog({
213 modal: true,
214 buttons: {
215 "Import": function() {
216 // Do the import of the data. The data in question is always
217 // in the textbox.
218
219 // Select all the entered hexes
220 select_string(text_area.val());
221
222 // Finally, close the dialog
223 $(this).dialog("close");
224
225 // Done with the tool
226 selected_tool = undefined;
227 }
228 },
229 close: function() {
230 // They didn't want to use this tool.
231 selected_tool = undefined;
232 }
233 });
234 });
235 });
236
237 // The actual text to selection import function used by that tool
238 function select_string(string) {
239 // Given a string of hex names, one per line, make a selection of all those
240 // hexes.
241
242 // This is an array of signature names entered.
243 var to_select = [];
244
245 // This holds the array of lines. Split on newlines (as seen in
246 // jQuery.tsv.js)
247 var lines = string.split(/\r?\n/);
248
249 for(var i = 0; i < lines.length; i++) {
250 // Trim and add to our requested selection
251 to_select.push(lines[i].trim());
252 }
253
254 // Add a selection with as many of the requested hexes as actually exist and
255 // pass the current filters.
256 select_list(to_select);
257 }
258
259 // And a tool for exporting selections as lists of hexes
260 $(function() {
261 add_tool("export", "Export...", function() {
262 // Make the export form
263 var export_form = $("<form/>").attr("title",
264 "Export Selection As List");
265
266 export_form.append($("<div/>").text("Select a selection to export:"));
267
268 // Make a select box for picking from all selections.
269 var select_box = $("<select/>");
270
271 // Populate it with all existing selections
272 for(var layer_name in layers) {
273 if(layers[layer_name].selection) {
274 // This is a selection, so add it to the dropdown.
275 select_box.append($("<option/>").text(layer_name).attr("value",
276 layer_name));
277 }
278 }
279
280 export_form.append(select_box);
281
282 export_form.append($("<div/>").text("Exported data:"));
283
284 // A big text box
285 var text_area = $("<textarea/>").addClass("export");
286 text_area.prop("readonly", true);
287 export_form.append(text_area);
288
289 // Add a download as file link. The "download" attribute makes the
290 // browser save it, and the href data URI holds the data.
291 var download_link = $("<a/>").attr("download", "selection.txt");
292 download_link.attr("href", "data:text/plain;base64,");
293 download_link.text("Download As Text");
294
295 export_form.append(download_link);
296
297 text_area.focus(function() {
298 // Select all on focus.
299
300 $(this).select();
301 });
302
303 text_area.mouseup(function(event) {
304 // Don't change selection on mouseup. See
305 // http://stackoverflow.com/a/5797700/402891 and
306 // http://stackoverflow.com/q/3380458/402891
307 event.preventDefault();
308 });
309
310 select_box.change(function() {
311 // Update the text area with the list of hexes in the selected
312 // layer.
313
314 // Get the layer name.
315 var layer_name = select_box.val();
316 if(!have_layer(layer_name)) {
317 // Not a real layer.
318 // Probably just an empty select or something
319 return;
320 }
321
322 // This holds our list. We build it in a string so we can escape it
323 // with one .text() call when adding it to the page.
324 var exported = "";
325
326 // Get the layer data to export
327 var layer_data = layers[layer_name].data;
328 for(var signature in layer_data) {
329 if(layer_data[signature]) {
330 // It's selected, put it in
331
332 if(exported != "") {
333 // If there's already text, put a newline first.
334 exported += "\n";
335 }
336
337 exported += signature;
338 }
339 }
340
341 // Now we know all the signatures from the selection, so tell the
342 // page.
343 text_area.text(exported);
344
345 // Also fill in the data URI for saving. We use the handy
346 // window.bota encoding function.
347 download_link.attr("href", "data:text/plain;base64," +
348 window.btoa(exported));
349 });
350
351 // Trigger the change event on the select box for the first selected
352 // thing, if any.
353 select_box.change();
354
355 export_form.dialog({
356 modal: true,
357 buttons: {
358 "Done": function() {
359 // First, close the dialog
360 $(this).dialog("close");
361
362 // Done with the tool
363 selected_tool = undefined;
364 }
365 },
366 close: function() {
367 // They didn't want to use this tool.
368 selected_tool = undefined;
369 }
370 });
371 });
372 });
373
374 $(function() {
375 // Set up the link to this page control
376 add_tool("link-to-page", "Link to this Page...", function() {
377
378 // We will provide the user with an alert box with the link to the
379 // hexagrap visualization map.
380
381 var link = (window.location.protocol + "//" + window.location.host
382 + "/" + window.location.pathname);
383
384 alert(link);
385 selected_tool = undefined;
386
387 });
388 });
389