ThinkGeo.com    |     Documentation    |     Premium Support

Question Regarding Excluding Features to Draw from a Layer

First, I’d like to thank everyone for the assistance provided thus far.  The discussion forums have been an invaluable resource in working with MapSuite MVC Edition.



I am currently working for a client on an AVL Replay map with standard playback controls and user defined playback criteria such as start time and update interval.  The client’s current AVL Replay map shows a vehicle’s position with a time-stamp.  The client would like the ability to display multiple points at a time on the map. For example, at any particular time the client would like the ability to see not only the current location and time, but also the next n points in the data set as well.  Looking through the various demos, I encountered this video on preventing certain features from drawing.  Is it possible to dynamically change what features are being drawn on map, as the demo uses criteria that are determined at compile time?  My thought is to create a featurelayer from the clients data, and then only render the current point in the playback along with the next n points, but that requires being able to tell the function attached to the event handler what the current point is.  I am open to suggestions on alternative means of implementing this in the event that this is not possible.

Hi Michael,



It’s our pleasure to assist you in the forums.

If you just means how to exclude some features during drawing the layer? Then, I would say the DrawingFeatures events should be fit for you, in this events, we can do the filter on  a feature collection parameter named “FeaturesToDraw” before we call the draw this layer in client side.

void austinStreetsLabelLayer_DrawingFeatures(object sender, DrawingFeaturesEventArgs e)
        {
            Collection<Feature> featuers = e.FeaturesToDraw;
        }



Besides, there is also a property named “FeatureIdsToExclude” for FeatureLayer should also be fit for your case, we can assign the value for it in an Ajax call, and then redraw the layer in client side.



If the above is not fit for you, would you let us know more details on your question or a sample is better?



Btw, I noticed your AVL application should be very similar with our  Vehicle Tracking Sample which is available in Map Suite 8.0 Product Center => Mvc Edition => Template Project. It’s a whole project including the source code.



I am hopeful that would be helpful.

Thanks,

Troy
 

Thank you, I apologize for the delay in responding. I’ll need to speak to the client about AVL Tracking Sample, as currently we are running version 7 of Map Suite, and they have access to all the Customer Information. For now, I’d just assume continuing with my current approach.  Never the less, thank you for mentioning that as something to look into. An example of setting the drawing features in an ajax call would be helpful though and much appreciated. I have also noticed a couple of oddities that I had questions about.



First, I’ve noticed after hooking up a function stub to the drawing features event for my layer, that the function seems to be called multiple times whenever the layer goes to render, each time with different numbers of features to draw in the event arguments list.  What exactly is happening here?



Second, my current approach is creating an InMemmoryFeatureLayer for storing the various locations of a vehicle after an ajax call fallowing the user selecting a particular route from list. In the ajax call I’m clearing out the layer’s features and rebuilding them with a new set of data based on the selected route.  Right now to test, I’m not worrying about filtering the data down to the 5 or so points the client wants in the end, and am simply rendering all the features in the layer. I’ve noticed that the first time the user selects a route, that all the features are being rendered on the map. However, if the user then selects a new route, none of the features get rendered.  I am definitely redrawing the layer after the ajax call returns. Is there another step besides clearing out the layer’s list of internal features that must be done when I change the features?  I don’t know if it could be somehow related to the number of features that are getting rendered in my simple test, as each route has potentially several hundred datapoints.



This is the code where I setup the layer and the overlay holding it:


protected void SetupAvlLayer(EventHandler<DrawingFeaturesEventArgs> handler)
        {
            //Create InMemoryFeature layer
            InMemoryFeatureLayer avlDataLayer = new InMemoryFeatureLayer();
 
            //Add DrawingFeatures event handler
            avlDataLayer.DrawingFeatures += handler;
 
            //Prevent labels on tile boundaries from being cut off
            avlDataLayer.DrawingMarginPercentage = 50;
 
            avlDataLayer.Open();
 
            //Add columns
            avlDataLayer.Columns.Add(new FeatureSourceColumn(“Id”));
            avlDataLayer.Columns.Add(new FeatureSourceColumn(“RouteId”));
            avlDataLayer.Columns.Add(new FeatureSourceColumn(“TimeStamp”));
            avlDataLayer.Columns.Add(new FeatureSourceColumn(“Longitude”));
            avlDataLayer.Columns.Add(new FeatureSourceColumn(“Latitude”));
            avlDataLayer.Columns.Add(new FeatureSourceColumn(“Speed”));
            avlDataLayer.Columns.Add(new FeatureSourceColumn(“Heading”));
            avlDataLayer.Columns.Add(new FeatureSourceColumn(“Route”));
 
            avlDataLayer.ZoomLevelSet.ZoomLevel01.DefaultPointStyle = PointStyles.City2;
            avlDataLayer.ZoomLevelSet.ZoomLevel01.DefaultTextStyle = TextStyles.City2(“TimeStamp”);
            avlDataLayer.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
 
            avlDataLayer.Close();
 
            //Create the overlay to hold the layer
            LayerOverlay avlOverlay = new LayerOverlay(“AvlOverlay”false, TileType.MultipleTile);
 
            //Add the layer to the overlay, and set visibility in overlay switcher
            avlOverlay.Layers.Add(“AvlLayer”, avlDataLayer);
            avlOverlay.IsVisibleInOverlaySwitcher = true;
 
            //Add overlay to the map’s custom overlay collection
            this.Map.CustomOverlays.Add(avlOverlay);
        }

This is the function I’m running with the ajax call after a user selects a route:


[HttpPost]
        [MapActionFilter]
        public ActionResult GetRouteData(Map map, GeoCollection<object> args)
        {
            if (args != null)
            {
                int id;
                int.TryParse(args[0].ToString(), out id);
 
                //Fetch route data
                using (DBContext context = new DBContext())
                {
                    model.RouteData = context.vAvlMapDatas.Where(p => p.avlrteId == id).ToList();
                }
 
                //Get overlay from map
                LayerOverlay avlOverlay = (LayerOverlay)map.CustomOverlays[“AvlOverlay”];
 
                //Get layer from overlay
                InMemoryFeatureLayer avlDataLayer = (InMemoryFeatureLayer)avlOverlay.Layers[“AvlLayer”];
 
                try
                {
                    avlDataLayer.Open();
 
                    //Clear the internal features
                    avlDataLayer.Clear();
 
                    try
                    {
                        avlDataLayer.EditTools.BeginTransaction();
 
                        //Create features from data and add to the layer
                        foreach (vAvlMapData dataPoint in model.RouteData)
                        {
                            Dictionary<stringstring> dict = new Dictionary<stringstring>();
                            dict.Add(“Id”, dataPoint.avlId.ToString());
                            dict.Add(“RouteId”, dataPoint.avlrteId.ToString());
                            dict.Add(“TimeStamp”, dataPoint.avlTimeStamp.ToString());
                            dict.Add(“Longitude”, dataPoint.avlLongitude.ToString());
                            dict.Add(“Latitude”, dataPoint.avlLatitude.ToString());
                            dict.Add(“Speed”, dataPoint.avlSpeed.ToString());
                            dict.Add(“Heading”, dataPoint.avlHeading.ToString());
                            dict.Add(“Route”, dataPoint.rteName.ToString());
 
                            Feature newFeature = new Feature(dataPoint.avlLongitude / 1000000.0, dataPoint.avlLatitude / 1000000.0, dataPoint.avlId.ToString(), dict);
                            avlDataLayer.EditTools.Add(newFeature);
                        }
                    }
                    finally
                    {
                        avlDataLayer.EditTools.CommitTransaction();
                    }
 
                    // Apply the projection to the layer
                    MappingUtility util = new MappingUtility();
                    try
                    {
                        util.WGS84toSphMercator.Open();
                        avlDataLayer.FeatureSource.Projection = util.WGS84toSphMercator;
                    }
                    finally
                    {
                        util.WGS84toSphMercator.Close();
                    }
                }
                finally
                {
                    avlDataLayer.Close();
                }
            }
            return PartialView(“Partial/_RouteDataPartial”, model.RouteData);
        }


Hi Michael,



Thanks for the details and seems you got two issues, let me answer them:

For the reason the DrawingFeature event will be triggered multi times, this is because the LayerOverlay are using the multitile mode by default and in this mode, each tile drawing will trigger this event and the event only includes the features within the current tile extent. But if we set a single tile mode for overlay, then this event should be triggered only once.



As for the second issue, we should put setting the projection for the layer before the adding or other operations. some codes like the below:




                InMemoryFeatureLayer avlDataLayer = (InMemoryFeatureLayer)avlOverlay.Layers["AvlLayer"];

                avlDataLayer.FeatureSource.Projection = util.WGS84toSphMercator.
Besides, when we add the feature with EditTools method, we still need to pass a projected feature for it. like:

                avlDataLayer.EditTools.Add(util.WGS84toSphMercator.ConvertToExternalProjection(newFeature));



With your original codes, the issue the second  time have some issue is because we stored the map including the layers in Session, we assign the projection for the layer behind the adding feature in the first time, but the next time, the layer is restored with the previous projection. So, the feature might be projected twice and result to some unexpected feature.



Please let us know if any questions.

Thanks,

Troy