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