yourcelf / olwidget

Javascript library to replace textareas that contain WKT data with editable OpenLayers maps, and a django app using it for django forms and admin.
Other
91 stars 44 forks source link

Using cluster:true, zoom_to_data_extent and individual feature styles are not respected #35

Closed skyl closed 14 years ago

skyl commented 14 years ago

If I uncomment the cluster option, I get clusters, but the style on individual features is gone and it looks like the map is zoomed to whatever is default and .. centered on the last point possibly .. either that or the default options ..

detail_map_options = { 'zoom_to_data_extent': True,

'cluster': True,

'default_zoom':12,

}

a_style = {'fill_color': '#5555FF', 'strokeColor': '#0000FF'} h_style = {'point_radius': 5,'fill_color': '#e0ffb8', 'strokeColor': '#669900'}

content = []
content.extend( [ foo.point, {'html': foo.html(), 'style': foo_style} ] for foo in fooset )
content.extend( [ bar.point, {'html': bar.html(), 'style': bar_style} ] for bar in barset )
olmap = InfoMap(
    content,
    options=detail_map_options
)
yourcelf commented 14 years ago

Hi skyl,

Thanks for the reports. I finally got some time to work on olwidget today. In the latest master, I've fixed the zooming problem with cluster.

I've also fixed the problem with individual feature styles; but with a caveat: because of the way openlayers implements clustering, it is not straightforward to simply use the styles in the attribute dict. When a cluster strategy is added, the original vector features are removed, and new clustered features are added which lack the attributes passed into the original features. It is thus necessary to do more complicated things to achieve this.

Here is a writeup: http://openflights.org/blog/2009/10/21/customized-openlayers-cluster-strategies/

Here is an example that uses a new option I've added ("overlayStyleContext") to enable custom styling of clusters, using OpenLayers' style symbolizers: http://olwidget.org/olwidget/doc/examples/info_cluster_per_point_style.html

I know this solution isn't ideal, but it seems OpenLayers doesn't currently support more elegant solutions. Please let me know if you encounter any other problems with this.

skyl commented 14 years ago

youcelf,

Aye, good work. Thank you very much.

The remaining problem is that I really want a separate Layer.Vector for different kinds of objects. I edited the list comps to make them more readable and generic.

skyl commented 14 years ago

I'm using a simple view like the following

def poi_detail(request, slug): waters = POI.objects.filter(point__distance_lte = (poi.point, D(km=10)), feature_class='H' ) data = { 'waters': [[poi.point, {'html': poi.popup_html(), 'style': style1}] for poi in waters], }

options = {}
options.update({'cluster':True})
options.update({
    'overlay_style': {'fillColor': "${specialAttributeHandler}", },
    'overlay_style_context': {
        'specialAttributeHandler': "function(feature) {return '#0000ff';}"
    }
})

olmap = InfoMap(data['waters'], options=options)
return render_to_response('geonames/show.html', locals(),
        context_instance=RequestContext(request)
)

If I just set 'fillColor': '#0000ff' directly, I get the blue color. But, if I try to set it through the specialAttributeHandler, I can't get anything to happen. Do I need to hack what I pass to the js olwidget.InfoMap contructor directly or am I supposed to be able to do it from the python constructor with some variant of what I have above?

yourcelf commented 14 years ago

Looks like this will require custom javascript in the template. "function(feature) {return '#0000ff'; }" is rendered as a string on the way out of Django's JSON serializer. Since functions are not part of the JSON spec, it would be necessary to do a custom coder that converts the python dict to JSON but preserves functions, or to try to do some tricks with "eval" that I'm not really interested in doing.

I'm not too thrilled by OpenLayers implementation here anyway. I'll try to see if I can figure out some other way to do this. In the mean time, you should be able to get this work by using a custom template like this:

<div id="{{ id }}"></div>
<script type='text/javascript'>
    new olwidget.InfoMap("{{ id }}", {{ info_array|safe }}, 
        OpenLayers.Util.applyDefaults({{ map_opts|safe }}, {
            overlayStyle: { fillColor: "${specialAttributeHandler}" },
            overlayStyleContext: {
                specialAttributeHandler: function(feature) {
                    return "#0000ff";
                }
            }
        })
    );
</script>

I also just fixed a couple of overlayStyleContext bugs that effect non-clustered maps, but unfortunately don't touch this.

skyl commented 14 years ago

yep, I've accomplished this by changing the template. Thanks for the hint about Util.applyDefaults. It seems that I could make another template that could do this generically something like:

No worries though, as my real problem was that I wanted fully separate vectorlayers so this is not something that I would be likely to use. Pardon any syntax errors and missteps above but I'm typing this in my eee with a little 3-high textbox.