def edit_layout(request, layout_id): """ Respond to the "/edit_layout/NNN/" URL. We let the user edit the given tableau layout. """ if not request.user.is_authenticated: return HttpResponseRedirect(reverse(settings.ADMIN_HOME_VIEW)) try: layout = TableauLayout.objects.get(id=layout_id) except TableauLayout.DoesNotExist: return HttpResponseRedirect( reverse("tableau_editor.views.main")) tableau = layout.tableau # Load the list of TableauLayoutViewPosition records for this layout into # memory, adding new records if they don't already exist. positions = [] anchorX = 10 anchorY = 10 views = TableauView.objects.filter(tableau=tableau) for view in views.order_by("-ordinal_rank"): try: position = TableauLayoutViewPosition.objects.get( tableauLayout=layout, tableauView=view) except TableauLayoutViewPosition.DoesNotExist: # Create a new view position record for this view. Note that we # have to set the view's rectangle up to have the aspect ratio of # the original view bounds, or else the view will be distorted when # it is displayed. proj = GlobalMercator() min_lat = float(view.min_lat) min_long = float(view.min_long) max_lat = float(view.max_lat) max_long = float(view.max_long) min_x,min_y = proj.LatLonToMeters(min_lat, min_long) max_x,max_y = proj.LatLonToMeters(max_lat, max_long) viewWidth = max_x - min_x viewHeight = max_y - min_y if viewWidth == 0: viewWidth = 1.0 if viewHeight == 0: viewHeight = 1.0 aspectRatio = viewWidth / viewHeight boxWidth = 40 boxHeight = boxWidth / aspectRatio position = TableauLayoutViewPosition() position.tableauLayout = layout position.tableauView = view position.min_x = anchorX position.min_y = anchorY position.max_x = anchorX + boxWidth position.max_y = anchorY + boxHeight position.save() anchorX = anchorX + 20 if anchorX > layout.width - 10: anchorX = 10 anchorY = anchorY + 20 if anchorY > layout.height - 10: anchorY = 10 positions.append(position) # See what the user wants to do. if request.method == "POST": if request.POST.get("update_size") != None: # The user clicked on the "Update" button to change the layout size # -> update the size of the layout. new_width = request.POST.get("width") if new_width != None: try: layout.width = int(new_width) except ValueError: pass new_height = request.POST.get("height") if new_height != None: try: layout.height = int(new_height) except ValueError: pass layout.save() return HttpResponseRedirect( reverse("tableau_editor.views.edit_layout", args=[layout.id])) if request.POST.get("fit_contents") != None: # The user clicked on the "Resize Layout to Fit Contents" button. # Calculate the new size for the layout. new_width = 10 new_height = 10 for position in positions: max_x = request.POST.get("view_"+str(position.id)+"_max_x") max_y = request.POST.get("view_"+str(position.id)+"_max_y") if max_x != None and max_y != None: max_x = int(max_x) max_y = int(max_y) if max_x > new_width: new_width = max_x if max_y > new_height: new_height = max_y layout.width = new_width layout.height = new_height layout.save() return HttpResponseRedirect( reverse("tableau_editor.views.edit_layout", args=[layout.id])) if request.POST.get("save") != None: # The user clicked on the "Save" button -> save the updated layout. for position in positions: min_x = request.POST.get("view_"+str(position.id)+"_min_x") max_x = request.POST.get("view_"+str(position.id)+"_max_x") min_y = request.POST.get("view_"+str(position.id)+"_min_y") max_y = request.POST.get("view_"+str(position.id)+"_max_y") if (min_x != None and min_y != None and max_x != None and max_y != None): position.min_x = int(min_x) position.min_y = int(min_y) position.max_x = int(max_x) position.max_y = int(max_y) position.save() return HttpResponseRedirect( reverse("tableau_editor.views.edit_tableau", args=[tableau.id])) if request.POST.get("cancel") != None: # The user clicked on the "Cancel" button -> return to the main # "Edit Tableau" page. return HttpResponseRedirect( reverse("tableau_editor.views.edit_tableau", args=[tableau.id])) # If we get here, we're displaying the form for the first time. Do so. menu_html = menus.generate(request, "Tableau Editor", "tableau_editor", "edit_layout") return render_to_response("tableau_editor/templates/edit_layout.html", {'menu_html' : menu_html, 'heading' : "Edit Layout for Tableau '" + tableau.name + "'", 'width' : layout.width, 'height' : layout.height, 'positions' : positions, }, context_instance=RequestContext(request))
def create_tableau(factory, location): """ Create a single tableau for a given location using a given factory. This function does the actual work of generating an individual tableau based upon the factory definition. It can be called directly to generate a desired tableau, or it can be called indirectly by the daemon (using the private 'create_tableau' API call) to generate tableaux en masse. Upon completion, we return None if the tableau-generation attempt was successful. Otherwise, we return a suitable error message explaining why the tableau could not be generated. """ # Get the location's outline. try: outline = Outline.objects.get(location=location) except Outline.DoesNotExist: # We can't create a tableau for a location without an outline -> # tell the user the bad news. return "Location has no outline." # Delete the existing tableau with this name, if any. Tableau.objects.filter(location=location, name=factory.tableau_name).delete() # Create the new Tableau for this location. tableau = Tableau() tableau.location = location tableau.name = factory.tableau_name tableau.meta_data = factory.tableau_meta_data tableau.bounds_render = factory.tableau_bounds_render tableau.save() # Create a single view for the tableau, covering the location's entire # extent. min_long,min_lat,max_long,max_lat = outline.outline.extent # Add a margin around the edges so that the location is easier to see. width = abs(max_long - min_long) height = abs(max_lat - min_lat) buffer = 0.02 * (width + height) / 2 min_long = min_long - buffer max_long = max_long + buffer min_lat = min_lat - buffer max_lat = max_lat + buffer # Ensure the calculated view bounds are allowable. if min_lat < MIN_ALLOWED_LATITUDE: min_lat = MIN_ALLOWED_LATITUDE elif min_lat > MAX_ALLOWED_LATITUDE: min_lat = MAX_ALLOWED_LATITUDE if max_lat < MIN_ALLOWED_LATITUDE: max_lat = MIN_ALLOWED_LATITUDE elif max_lat > MAX_ALLOWED_LATITUDE: max_lat = MAX_ALLOWED_LATITUDE if min_long < MIN_ALLOWED_LONGITUDE: min_long = MIN_ALLOWED_LONGITUDE elif min_long > MAX_ALLOWED_LONGITUDE: min_long = MAX_ALLOWED_LONGITUDE if max_long < MIN_ALLOWED_LONGITUDE: max_long = MIN_ALLOWED_LONGITUDE elif max_long > MAX_ALLOWED_LONGITUDE: max_long = MAX_ALLOWED_LONGITUDE # Create the view. view = TableauView() view.tableau = tableau view.ordinal_rank = 1 view.name = location.display_name view.min_lat = "%0.4f" % min_lat view.max_lat = "%0.4f" % max_lat view.min_long = "%0.4f" % min_long view.max_long = "%0.4f" % max_long view.meta_data = factory.view_meta_data view.bounds_render = factory.view_bounds_render view.save() # Add the factory's filter(s) to the tableau's view. for factory_filter in factory.tableaufactoryviewfilter_set.all(): filter = TableauViewFilter() filter.tableauView = view filter.type = factory_filter.filter_type filter.value = factory_filter.filter_value filter.meta_data = factory_filter.filter_meta_data filter.draw_bubbles = factory_filter.filter_draw_bubbles filter.polygon_render = factory_filter.filter_polygon_render filter.bubble_render = factory_filter.filter_bubble_render filter.save() # Calculate the aspect ratio for the tableau's view. proj = GlobalMercator() min_x,min_y = proj.LatLonToMeters(min_lat, min_long) max_x,max_y = proj.LatLonToMeters(max_lat, max_long) viewWidth = max_x - min_x viewHeight = max_y - min_y if viewWidth == 0: viewWidth = 1.0 if viewHeight == 0: viewHeight = 1.0 aspectRatio = viewWidth / viewHeight # Create a single layout for the tableau. The size of the layout is # based on the view's aspect ratio. layout_width = LAYOUT_MAX_WIDTH layout_height = layout_width / aspectRatio if layout_height > LAYOUT_MAX_HEIGHT: layout_height = LAYOUT_MAX_HEIGHT layout_width = layout_height * aspectRatio layout = TableauLayout() layout.tableau = tableau layout.width = layout_width layout.height = layout_height layout.save() # Create a single TableauLayoutViewPosition record, positioning the view # within the layout. position = TableauLayoutViewPosition() position.tableauLayout = layout position.tableauView = view position.min_x = 0 position.min_y = 0 position.max_x = layout_width position.max_y = layout_height position.save() # Finally, tell the caller that the tableau was successfully generated. return None