ThinkGeo.com    |     Blog    |     Wiki    |     Support

Dynamically change Marker size

I know Markers are rather basic, but I did not find them used in any of the samples and the Wiki information was not helpful at all. I want to vary the marker size depending on zoom level (as a non-clustering approach to avoiding crowding). It seems that the AdjustedScalingImageStyle sample may be helpful, but I’m missing a bunch of the essential background material to evaluate that possibility.

  • Is the Marker class already smart enough to do this for me? (I think that answer is “No.”)
  • Which properties, if any, will change the drawn size of the marker image, and with what effect?
  • Does it matter what type of SourceImage is being drawn?
  • Do marker styles figure into this question?
  • Are there potential surprises I should be aware of, like issues with screen vs. world coordinates?

Hi JWhitmire,

  1.   As AdjustedScalingImageStyle sample, if you want to change the makers count and size when you zoom in / out, you just only inherit “Style” class and override “DrawCore”. But if you want change the maker’s size only, you can use following statements:
    
            Map1.MapUnit = GeographyUnit.DecimalDegree;
    
         WorldMapKitWmsSilverlightOverlay baseOverlay = new WorldMapKitWmsSilverlightOverlay();
         Map1.Overlays.Add(baseOverlay);
    
         InMemoryMarkerOverlay markerOverlay = new InMemoryMarkerOverlay();
         markerOverlay.ZoomLevelSet.ZoomLevel01.DefaultMarkerStyle.ImageSource = new BitmapImage(new Uri("/theme/marker_blue_shadow.png", UriKind.RelativeOrAbsolute));
         markerOverlay.ZoomLevelSet.ZoomLevel01.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level05;
         markerOverlay.ZoomLevelSet.ZoomLevel05.DefaultMarkerStyle.ImageSource = new BitmapImage(new Uri("/theme/marker_red_shadow.png", UriKind.RelativeOrAbsolute));
         markerOverlay.ZoomLevelSet.ZoomLevel06.DefaultMarkerStyle.ImageSource = new BitmapImage(new Uri("/theme/marker_yellow_shadow.png", UriKind.RelativeOrAbsolute));
         markerOverlay.ZoomLevelSet.ZoomLevel06.DefaultMarkerStyle.ImageWidth = 55d;
         markerOverlay.ZoomLevelSet.ZoomLevel06.DefaultMarkerStyle.ImageHeight = 32d;
         markerOverlay.ZoomLevelSet.ZoomLevel06.DefaultMarkerStyle.ImageOffsetX = -28;
         markerOverlay.ZoomLevelSet.ZoomLevel06.DefaultMarkerStyle.ImageOffsetY = -32;
         markerOverlay.ZoomLevelSet.ZoomLevel06.ApplyUntilZoomLevel = ApplyUntilZoomLevel.Level20;
    
         Random random = new Random(DateTime.Now.Millisecond);
         for (int i = 0; i < 10; i++)
         {
             double x = -94.558 - random.NextDouble() * 20;
             double y = 39.078 + random.NextDouble() * 10;
             markerOverlay.FeatureSource.InternalFeatures.Add(new Feature(new PointShape(x, y)));
         }
         Map1.Overlays.Add(markerOverlay);
    
         Map1.ZoomTo(new PointShape(-100, 40), 5);
    
  2.   All formats which are supported by BitmapImage class are available, please refer to https://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapsource(v=vs.110).aspx. 
    
  3.    I think you will pay attention to the projection information in your project, you can convert a coordinate to another projection coordinate such as “Proj4Projection” class.
    

Thanks,

Thanks, that helps a bit. A new obstacle that now enters is that the non-sizing code is using SimpleMarkerOverlay (which has no ZoomLevelSet) and its Markers collection so that each marker image can be individually changed (based on other criteria). Switching to InMemoryMarkerOverlay hits a snag trying to create each new marker since it apparently has no place to store them, and my InMemoryMarkerOverlay.FeatureSource does not have the member InternalFeatures that your example uses. The issue now seems to be even more complicated than I feared.

Hi JWhitmire,

I think you should still want to switch to InMemoryMarkerOverlay, but I am not sure why you cannot find InternalFeatures, could you please make sure your version is from our latest package? And please let us know your detail version.

Regards,

Don

I discovered late yesterday that even though we have Map Suite 9 installed, the project was still using version 6! Fixing that should make a nice difference, but I still have the issue of InMemoryMarkerOverlay not having a container for Markers, only Features, and Features don’t have individual images (at least, not that I have found). I have 20+ different images to display on my Markers and each Marker is subject to having its image changed dynamically.
In the code samples, I see use of the SimpleMarkerOverlay for the same features we are using and I see the use of InMemoryMarkerOverlay for the feature I want to add, but I don’t see any way that I can have both in one place.

Hi JWhitemire,

Just like I talked before, you should want to override the style, then write custom code to draw target image for each feature like this:

http://wiki.thinkgeo.com/wiki/source_code_serviceseditionsample_scalingimagestyle_cs_090728.zip

You should want to set a special value in the feature.CustomValues, then in the DrawCore, you can know which feature should draw which image, and then draw it by canvas.Drawxxxxx API.

Wish that’s helpful.

Regards,

Don

Multiple obstacles here.

  1. I can’t get version 9 to correctly activate. It builds fine in VS Debug configuration, but not in Release configuration.
  2. While I am stuck in version 6, its Feature class does not have a CustomValues member. Is there a similar approach for version 6?
  3. Assuming that we do get version 9 working, are you suggesting that I put the Marker as a CustomValue of the Feature? I need the functionality that goes with Marker.ImageSource and Marker.Popup. Do they connect automatically when I create the Marker or do they require wiring found only in the SimpleMarkerOverlay?
  4. I can understand what goes on inside ScalingImageStyle, but I don’t yet understand enough to know which canvas.Drawxxxx method to use if I add it. I need you to explain it in a more elementary context. I also need clarification on how to decide whether to use that style or the ZoomLevelSet member.
  5. A bunch of the code assumes it is working with a Marker, based on the use of SimpleMarkerOverlay. Why does the InMemoryMarkerOverlay not have functionality for using Markers? It seems to be only an InMemoryFeatureOverlay, not a xxxxMarkerOverlay. If I don’t use Markers, what can I use instead?

Hi JWhitemire,

  1. If you met the activation problem for version 9, please contact your sales to solve it.
  2. Sorry the version 6 is a very early version, I think upgrade to latest version is a better choice.
    3,4,5 In fact the SimpleMarkerOverlay is simple to use, so it cannot get more override just like your requirement, but if you choose InMemoryMarkerOverlay you need to write some custom code your self. It’s not something like marker, it’s just the feature like all of our other layers. And you hadn’t mentioned Popup before, I think popup should be a standalone GeoPopup, you need custom implement that also.

Regards,

Don

  1. You missed the significance of #4: I need something more tutorial than the instruction you have provided. I had expected that I would need “some custom code,” but I don’t know what class to start from.
  2. Since the InMemoryMarkerOverlay assumes a single image for all its markers (not to be confused with instances of Marker), I suspect I could get what I want by using an overlay for each of the 20+ images, but I don’t know if that is a feasible idea.
    (a) Layers versus Overlays is another question that needs consideration there, and I wonder if I could add Layers to that Overlay since it has none. Would that work? Is there a performance difference worth considering?
    (b) I also don’t know if I can get the rest of the needed Marker functionality from a Feature subclass. If you lead me through the creation of a Feature with a popup, I may be able to figure out the rest of it.

Perhaps a very helpful thing would be a version of the ScalingImageStyle sample using the InMemoryMarkerOverlay with popup capability.

Hi JWhitemire,

Attached is the sample shows one way to change the marker size with zoom level.

InMemoryMarkerOverlaySample.zip (1.5 MB)

Thanks,
Peter

Thank you, Peter. That helps answer my questions about the 20 marker images and about associating a given marker with its matching Feature.

  • The scaling with zoom level is still a bit obscure since I only see a size change on two zoom levels. Can you show me how to shrink the image as the user zooms out, with bounds on the image size? Also, please explain the relationship between your use of ScaleTransform and the ScalingImageStyle sample.
  • I am still lost on the popup since the popups in your sample do not pop up. I assume they should do so on MouseEnter.

Update: I have done a lot of experimenting with your latest sample to see what I can and cannot do, and I think you have shown me that it is not possible to get what I want.

  • I can’t use the SimpleMarkerOverlay because it doesn’t support styles, scaling, or zoom levels.
  • I can’t use the scaling style in the InMemoryMarkerOverlay because it derives from the wrong class ancestry.
  • I can’t use the popups in InMemoryMarkerOverlay because they don’t work.
  • I can’t use the ScaleTransform because it causes the marker to disappear at each end of the zoom range.
  • Dynamically updating the content of the marker popup in the InMemoryMarkerOverlay requires the use of “ugly” coding to access the associated Feature that provides the dynamic content, and I can’t tell what else is needed to get the popup to show.
  • The MouseEnter event for InMemoryMarkerOverlay looks promising, but I can’t use it because it is never raised.
  • The rectangle for triggering the MouseEnter event for the Marker in InMemoryMarkerOverlay is much larger than I expected and there is nothing available that tells me why.

With all the flexibility and power you seem to have put into the rest of the package, I don’t understand why you designed my scenario out of the realm of possibility. (Of course, if your documentation actually told me anything useful, I might develop a more positive impression.)

Hi JWhitmire,

The sample just show the silverlight edition can do what you want. Please check the answers below.

- I can’t use the SimpleMarkerOverlay because it doesn’t support styles, scaling, or zoom levels.
The SimpleMarkerOverlay is the sample way to display the markers, but we can create a class derived from it and override the GetDrawingMarkersCore method to achieve the requirements.

- I can’t use the scaling style in the InMemoryMarkerOverlay because it derives from the wrong class ancestry.
The sample Don provided before is based on the Service Edition and in Silverlight Edition the MarkerStyle must be a subclass of MarkerStyle. And we can do the similar thing as scaling style to change the marker size like the sample I provided.

- I can’t use the popups in InMemoryMarkerOverlay because they don’t work.
Sorry for the mistake in the sample, please try the set the popup when create the marker as below:

- I can’t use the ScaleTransform because it causes the marker to disappear at each end of the zoom range.
It’s not the only way to use the ScaleTransform to change the size of markers, we can also change the markers size when create the markers.

- The MouseEnter event for InMemoryMarkerOverlay looks promising, but I can’t use it because it is never raised.
Please binding the MouseEnter event for the marker instead.

- The rectangle for triggering the MouseEnter event for the Marker in InMemoryMarkerOverlay is much larger than I expected and there is nothing available that tells me why.
I don’t understand what the “MouseEnter event for the Marker in InMemoryMarkerOverlay is much larger than I expected” means. Could you please provide more information?

Also, you can download the “How Do I” samples from Product Center or view http://wiki.thinkgeo.com/wiki/map_suite_silverlight_edition_all_samples#map_suite_silverlight_edition_how_do_i_samples to know more.

Thanks,
Peter

[quote=“Peter, post:13, topic:8091”]The SimpleMarkerOverlay is the sample way to display the markers, but we can create a class derived from it and override the GetDrawingMarkersCore method to achieve the requirements.
[/quote] If that is feasible, please show me an example I can use. From what I have seen in the ScalingImageStyle sample, we would have to add a ZoomLevelSet and all its connections. That is much more than just overriding the one method you mention. Extending SimpleMarkerOverlay would be my preferred approach since it already provides all the other functions I need, but adding ZoomLevelSet seems to be very formidable.

[quote=“Peter, post:13, topic:8091”]The sample Don provided before is based on the Service Edition and in Silverlight Edition the MarkerStyle must be a subclass of MarkerStyle. And we can do the similar thing as scaling style to change the marker size like the sample I provided.[/quote] That information helps clear a lot of my confusion! Are you saying that I should not be trying to use ScalingImageStyle? If that approach can be used with your CustomMarkerStyle, please show me.

[quote=“Peter, post:13, topic:8091”]please try the set the popup when create the marker as below[/quote] Making that change (and the related one in MainPage that you did not mention) causes the InMemoryMarkerOverlay.MouseEnter event to work, even though I can see now why I would not need it. However, the popup still does not appear. (Did you test this example?) The Marker.MouseEnter event is raised, but I do not know what to use in that handler to show the popup. The method we use in the Markers collection of SimpleMarkerOverlay is not available (since we have no Marker collection in InMemoryMarkerOverlay) and you don’t show me what to use instead.

[quote=“Peter, post:13, topic:8091”]
It’s not the only way to use the ScaleTransform to change the size of markers, we can also change the markers size when create the markers.
[/quote] I have learned some idea how this might be done. I was surprised to realize that the Markers in InMemoryMarkerOverlay are transient; you recreate every visible Marker every time any Marker event occurs. I did not expect that since the Markers in SimpleMarkerOverlay are persistent, and I am concerned about the performance when I have a large number of Markers visible. It also raises another question for me. My Marker images need to change in response to external events that are related to the associated Feature. How do I cause the Marker to be redrawn with its new image when no marker event has occurred?

[quote=“Peter, post:13, topic:8091”]I don’t understand what the “MouseEnter event for the Marker in InMemoryMarkerOverlay is much larger than I expected” means. Could you please provide more information?[/quote] I found the cause for this. It was the large empty space in the marker images. I replaced them with my images and the bounding rectangle for the MouseEnter event is now what I expected.

Your answers still assume that I understand the Map Suite architecture much better than I do. The purpose of the documentation is to give me that understanding, but yours does not and I have to ask you to teach me instead. I am still a beginner. Please treat me like a beginner. I can learn fast, but only if you give me the information to learn.

Hi JWhitmire,

I took some time to create another sample based on the SimpleMarkerOverlay which has the similar function like ScallingImageStyle, please check it out and try to modify it based on your requirements.

The popups in the previous sample can work well on my side, now please try this new sample and ignore that one if it’s not helpful.

In the screenshot there are two images, the one on the left corner is the smaller markers and the right one shows the marker on the high level. While the mouse hovering over the marker the popup will be visible.

DynamicallyChangeMarkerSize.zip (28.7 KB)

Thanks,
Peter

:gift: That is what I needed! Thank you, I think I can find my way from here. Only three questions remain:

  1. When an external event happens and I need to change the marker image, will it update on the map automatically or do I need to do something to cause the refresh?
  2. When I set the ImageOffsetY to put the image above the point, the popup appears over the image, which I would expect. Moving the mouse around in the marker area while it is over the popup causes the popup to disappear and reappear unpredictably. Is there something I can do to stop the popup from disappearing until the mouse leaves the marker area?
  3. Your use of markerSize in GetDrawingMarkersCore seems to assume a square image, but the images are obviously not square. What is the Marker doing to adjust the displayed image when the aspect ratio of ImageHeight and ImageWidth is different from the aspect ratio of the ImageSource?

Hi JWhitmire,

Please check the answers:

Yes we need to call Map.Refresh() method after change the markers’ image like below:
Map1.Refresh();

Please try the reflection to remove the MouseLeave Handler.

In the sample, I just want to show how to change the size of the marker without considering if it’s not square. The image stretch with the Uniform.

Thanks,
Peter

The language barrier is killing us.
[1] Map1.Refresh() I understand. I have that working. :white_check_mark:
[2] Using “Reflection to remove the MouseLeave handler” I do not understand. :confused: However, it does suggest an idea: Could the disappearing happen because the mouse position is considered to have entered the popup and, therefore, left the marker even though it is still within the marker bounds? If so, a MouseLeave handler for the Marker could check to see if the mouse location has actually left the Marker’s area. If that is possible, how would I control whether the popup remains displayed or closes?
[3] I also do not understand “The image stretch with the Uniform.” :confused: I don’t see the images being deformed, which indicates that the Marker may be only comparing one image dimension with the value of markerSize. I would guess that it uses the larger image dimension. I will ask the question this way: If I use an image that is 80x20 and a value of 40 for markerSize in your sample, what size image will I see? 40x10? 40x40? 160x40?

Hi JWhitmire,

For the #1, The following figure shows the marker’s area(the red rectangle), only the mouse on the marker the popup displays, otherwise the popup disappears. If you want to control when the popup disappear/display, I guess you need to handle by yourself.

For #2, the following is the theme of the marker, and the image stretch with the default value(As I mentioned before). The size of the image rendered should be based on the Image size, if you want to render as the different behavior, I think you need to override the default theme.

Thanks,
Peter

You did not understand the question. I was asking you to explain your previous answer:

[quote=“Peter, post:17, topic:8091”]
Please try the reflection to remove the MouseLeave Handler.
[/quote] I do not understand what you mean by this instruction and I still desire an answer to the question about the popup disappearing and reappearing as the mouse moves around within the marker image.

If I move the mouse from below the popup tail to above it within the inner circle of this image, the popup will disappear and then reappear. I do not think that is the expected behavior. With a smaller popup content or a larger image, the popup covers more of the image and the behavior is worse. When the mouse is over both the popup and the marker image, the popup will disappear and reappear erratically. Is there a way to fix that?

[New question: In your picture, the popup Close button covers the last character of the popup content. Instead of “Green Marker,” the popup shows “Green Marke.” Is that supposed to happen?]