ThinkGeo.com    |     Documentation    |     Premium Support

Add rotation to PointMarkerStyle based on some feature column

Hello,


I am currently in the process of converting our app from MapSuite Web Forms edition to MVC and I want to move some of the logic from javascript server-side. Previously, we have been creating the feature layer using OpenLayers vector layer and GML format. I am now instead using InMemoryMarkerOverlay.


One of the things I need to accompish is this:



        
  • Each marker should be rendered with (1) a specific image AND  (2) rotation based on column values in the feature. I am using ValueMarkerStyle with a "color" column name to accomplish (1), however, based on another column value "angle" I need to apply a rotation to the WebImage.  With OpenLayers I was able to do this using a style map to set the correct image based on the value of "color", and access the "angle" column value of the feature using the special syntax "${angle}".

        

        How can I accomplish the same server-side? This post shows something similar:

        gis.thinkgeo.com/Support/DiscussionForums/tabid/143/aff/12/aft/9565/afv/topic/Default.aspx 

        

        I tried something like the following but it is not working:



var markerStyle = new ValueMarkerStyle("color");
var image = new WebImage("red_image.png");
image.RotationAngle = float.Parse("[#angle#]");
markerStyle.ValueItems.Add(new MarkerValueItem("red", new PointMarkerStyle(image)));
 



        
  • Secondly, I am contemplating whether to use InMemoryMarkerOverlay or InMemoryFeatureLayer. For some reason I am seeing slightly better performance (less lag when panning/zooming) with the InMemoryFeatureLayer with about 900 features, however, I am uncertain whether it will support my requirements to use marker popups and feature selection? I would like your advise on this. Also, when I use the InMemoryFeatureLayer there is some rendering issue with the features. When I pan the map the visible markers "flicker" on the screen until they move to the new positions.

  •     
  • Lastly, how do I change the mouse cursor into a hand/pointer when someone mouse over a feature/marker? Again, I was able to set this with the OpenLayers style map.


I hope you can help. If there is some way to accomplish the above by "applying" the style client side, while still managing features/layer on the server I suppose that would be okay too.


Thank you,

Sindre



I have an idea for you.  You could create different images rotated at different angles, and use these distinct images to create your rotations.

Thanks, but I don’t see how that would help. I would still need to figure out the angle for the feature when the style is applied. Is there really no way to achieve this? Some “OnStyleApplying” event/method or something I could override to check the column values of the feature and apply the correct angle accordingly?

Just to let you know, I figured out a way around this by using multiple “nested” ValueMarkerStyle’s. The first ValueMarkerStyle targets the “color” property and has a marker style ValueMarkerStyle which targets the rotation. Thus, I was able to select both the correct image and apply the RotationAngle based on column values on the feature.

 Hello Sindre,


 
 Thanks for sharing your experience!
 
 And for your second question, yes using InMemoryFeatureLayer will have better performance because InMemoryMarkerOverlay we will pass all the points information to client side then initialize the marker by OpenLayer, it will cost time, also InMemoryFeatureLayer you can use ClusterMarkerStyle to get better performance facing too many markers.
 
 For your third question, you can register the mouseover event in the client side, then change the mouse cursor by JS, please check the code below:

<script language="javascript" type="text/javascript">
 
         var OnMapCreating = function (map) {
             OpenLayers.Layer.Markers.prototype.addMarker = function (marker) {
                 this.markers.push(marker);
  
                 if (this.opacity != null) {
                     marker.setOpacity(this.opacity);
                 }
  
                 if (this.map && this.map.getExtent()) {
                     marker.map = this.map;
                     this.drawMarker(marker);
                 }
  
                 // Register the mouse hover event
                 marker.events.register('mouseover', marker, function (evt) {
                     document.getElementsByTagName("body")[0].style.cursor = pointer;
                 });
             }
         }

 Regards,
 
 Gary

Thanks Gary. Works great with the cursor workaround. Will it work with features created in InMemoryFeatureLayer as well? 
  
 I still experience this issue which I described in my first post: "Also, when I use the InMemoryFeatureLayer there is some rendering issue with the features. When I pan the map the visible markers "flicker" on the screen until they move to the new positions." 
  
 When I drag the map and release the mouse button, the feature show on the previous position for a split second while the map re-renders it seems. This does not happen with the InMemoryMarkerOverlay.

Hello Sindre, 
  
 Client side mouse over event is not working on features, because openlayer doesn’t have such thing as a feature, so when we draw a feature we will process it as a image in the server side first, draw a image in the client side, that’s one reason InMemoryFeaturelayer is faster than InMemoryMarkerOverlay. And if you want to determine if your mouse is hover a feature, the only way is call ajax each time when you mouse move, and check if mouse location is intersection with the shape, that costs too many resource and is unacceptable. 
  
 About the issue you mentioned, can you provide a sample that I can recreate your problem? 
  
 Regards, 
  
 Gary

Gary, 

Thanks. 



Regarding the issue, please see attached code. 



The "flickering" bug is very visible. Just drag the map and you will see the two red markers flicker. 



  @{Html.ThinkGeo().Map("Map1", new System.Web.UI.WebControls.Unit(100, System.Web.UI.WebControls.UnitType.Percentage), 510)                         .WebConfigRegisterMode(WebConfigRegistrationMode.Manual)                         .ResourceDeploymentMode( ResourceDeploymentMode.Manual)                         .CurrentExtent(-12400000, 12000000, 1240000, -1240000)                         .MapBackground(new BackgroundLayer(new GeoSolidBrush(GeoColor.FromHtml("#E5E3DF"))))                         .MapUnit(GeographyUnit.Meter)                         .CustomOverlays(overlays =>                         {                             //overlays.WorldMapKitWmsWebOverlay();                             overlays.GoogleOverlay("GoogleMap", GoogleMapType.Normal).IsBaseOverlay(true);                              var projection = new ManagedProj4Projection(                                 ManagedProj4Projection.GetWgs84ParametersString(),                                 ManagedProj4Projection.GetGoogleMapParametersString());                                                          projection.Open();                             InMemoryFeatureLayer mapShapeLayer = new InMemoryFeatureLayer();                             mapShapeLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.CreateSimplePointStyle(PointSymbolType.Circle, GeoColor.SimpleColors.Red, 20);                             mapShapeLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;                             mapShapeLayer.InternalFeatures.Add(projection.ConvertToExternalProjection(new Feature(new PointShape(-70, 20))));                             mapShapeLayer.InternalFeatures.Add(projection.ConvertToExternalProjection(new Feature(new PointShape(-40, 30))));                             projection.Close();                                                          overlays.LayerOverlay("OverLayer").TileType(TileType.SingleTile).IsBaseOverlay(false).Layer("InMemoryFeatureLayer", mapShapeLayer);                          })                         .Render(); 


 


Update: 


I noticed that the problem is related to the TileType setting. When using TileType.MultipleTile the problem is alleviated. Although, if you move the map all the way to the bottom (South), so that the two markers disappears from the viewport they will flicker/appear for a split second over Antarctica.


Any ideas?


Also, I would like to ask you what is the recommended way to add a InMemoryFeatureLayer? To CustomOverlays as a LayerOverlay or to the Layers collection of the DynamicOverlay? Is there a difference beside semantically? Performance wise?


I look forward to your prompt feedback.


 



Hello Sindre, 
  
 Thanks for the further information, the problem is using single tile, in single tile, every pan means the extent changes, so the map will totally redraw, but InMemoryFeatureLayer won’t draw until the mouse release. So this make the “flickering”, but this is for improve the singletile performance, so we won’t modify this. 
  
 And you mentioned when you use MultipleTile, the problem is “alleviated”, so you mean the problem gone? Or just disappear not frequency? I have tested in my side with your code, with MultiPleTile, everything going fine, can you guide me how to recreate your problem? 
  
 To add a InMemoryFeatureLayer, you can added into both overlays, and there isn’t any performance difference just different overlay draw on different z-index and have different drawing order, most time we will add it into LayerOverlay. 
  
 Regards, 
  
 Gary