Select to view content in your preferred language

Creating a FeatureLayer from a FeatureCollection. Base64 in Internet Explorer

3249
4
12-07-2010 07:55 AM
AxelSchaefer
Emerging Contributor
Hi. This is difficult.

I'm building a client, where the data is pushed to dynamically (via an upload mechanism, but that is not the topic of this post). My way to implement is the following:

  • I am using Version 2.1 of the API.

  • I am using the FeatureLayer with the esri.layers.FeatureLayer(featureCollectionObject, options?) constructor.

  • I want to use a class-break symbolization. Ideally I don't want to do it myself.

  • I want to use an existing map service for the symbolization rules and the featureCollection.

  • I have to use InternetExplorer.

  • I have some problems with the base64 encoding in the PictureMarkerSymbols.


What is the error? My Picture Marker Symbols are not shown in Internet Explorer.

What do I do? Here is the example for you to reproduce. This example is based on the Notes MapService at http://sampleserver5.arcgisonline.com/ArcGIS/rest/services/Notes/MapServer/.

(1) Create a json object that will be my data.

var myjson = { "displayFieldName": "name", "fieldAliases": { "name": "Name" }, "geometryType": "esriGeometryPoint", "spatialReference": { "wkid": 4326 }, ...


This JSON is an example content. You can grab the whole JSON from here: http://sampleserver5.arcgisonline.com/ArcGIS/rest/services/Notes/MapServer/0/query?text=&geometry=&g...

The variable is filled with that value (the parameter f=json).

(2) Create a feature set from that JSON object:

var myFeatureSet = new esri.tasks.FeatureSet(myjson);


(3) Create a layer definition for the featureCollection:

var mylayerDefinition = { "id": 0, "name": "Notes", "type": "Feature Layer", ...


This JSON is an example content. You can grab it from here: http://sampleserver5.arcgisonline.com/ArcGIS/rest/services/Notes/MapServer/0?f=json&pretty=true

The variable is filled with that content (without the parameter pretty=true).

(4) Create a featureCollection from the layerDefinition and the featureSet:

var featureCollection = {
   layerDefinition: mylayerDefinition,
   featureSet: myFeatureSet
};


(5) Create a FeatureLayer from that FeatureCollection. For example:

featureLayer = new esri.layers.FeatureLayer(featureCollection, {
  mode: esri.layers.FeatureLayer.MODE_ONDEMAND,
  outFields: ["objectid", "note", "link", "name", "email", "phone"]
});



(6) Add that FeatureLayer to your map.

map.addLayer(featureLayer);



What happens?

The client will show your data from the myFeatureSet. Later I will replace that with my uploaded content. The data will be symbolized by the definitions in the LayerDefinition. So I don't need to make a custom renderer from my object.

Everything works fine in Firefox, Chrome and Opera.

Unfortunetaly that doesn't work in Internet Explorer.

Why?

Because the PictureMakerSymbols in the Service are encoded with base64. IE doesn't support that yet. The symbol is places on the make like this (output from Firebug):

[HTML]<image fill-opacity="0" stroke="none" stroke-opacity="0" stroke-width="1" stroke-linecap="butt" stroke-linejoin="miter" stroke-miterlimit="4" x="373.3333333333333" y="206.33333333333334" width="37.33333333333333" height="37.33333333333333" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAABXhJREFUWIXt2GtsFFUUwPH/3ZnZO93uYluKFNo6uyC0pVJrUaTKM1FeMWpZI1/BD2iiMSqKCmhCRa0EMDHRGAxPrSboiq9QsEahQhUDgihvkL3EhJogNRaU6VbXD7NdOnQL3bU+EjlfdvfOzL2/nHPPzO7q/EdD/7cBPcVlWLrxt8Esy4orpUSm1/c5zLKsOED0zRbEzZnP0yewTsyy+1oIj29xjWeatb8E65odV2hAxkV0IiOYZVnxUH47n72UAAnAk3gV9vmxfwLmzk5LzxgPtLRWUtB/D9H3FcE7MivnJWEu0EUwZ37Lo/WXUooHN1MwYE/inHQ5l4BVDiqJt3rPOZt5QktqjOa8PXbiVooHN+EPnMbfr/kCPEQ3K4JT0s9aN5hlWfHdb0UvikHAvsPTKC9tYOiQRiJ1kvCC8xgERGolAOFn7HQ8PcOc0cRkXbtLwIkfKjn76wDKyhopL29IIsJP2cRs+GCJpOZpmw21kvBim1PHnTmiTYrg+PSy1g2mlBLoxDsxCPhq592MvnE9V4X2uLKSzM4iJzvj5gTxyEMARBZKwnV28pxrhrejVG9ZF8A6N3rtR3NYcFstzc13MW5CPaOr17sxHpKlPvbtrdTUNuLR4YNFUW5fBNOesGmokxz4VLL/Y5j2cAEfrVMEx/Q+ay6YUkpYlhXv6IihSZtxk+pTYhCJjDxns2d9E0OrnLGYDWjgy4dbHirGMM5SNuUkoEBIojvaCN7YO1y3UobaCzl0cD8L37ifxbNfTmJ2RiT0n8zg0GEGDz2ULFN4iU1kniS81Ca81CbyqKSmDq4oPgpCAnnOxEICXo6818awOy+N6wbbcrJZWDuseG7/6c5RAZEFkvDzNogPiTwhCS8hiQGwrge1exxW1eeElwNkOyAB4AUMflVn8YVMjKJcors0gqOcfdwTMGVXKqXEpo0b409n11D74AZnsGuHeiC8zCYyV+LPz2PK/NPAPmCQC4NH45dDv9OvxI9vyBWJ5TRAI7rNAF+IYBUps9fjnV8pJTZ+khuvfRiqZ9nJkoaX2TQsHsRNc7IJLz/tnCzyXBiAU99lkT9So19pAiMcUOyHvRhFN0D2MMBDdHcF9z7ij69Ys8+Fu+gj6VRrK1PvmcKmNZuJzJUMmTyd66ZuZdpTgIgBgS4YHbvN5NRRncIqyB95HgMG4MGO7kWGqp1lhdNNwcqdKct5UVjigvjPP15NePlZEF93w4DB8eYcBpa148uDwlFenPRqycXbDu8nMLwSOWSM69iM2Ta57Sapbm+9+nYxaaZkdxMuzB8dkiPbcyiZ2EZoLIDpwoBO67eHya0YQaBkNCBAON302LOFGIYXX9ZxWr3nUq55SZhSSmBZ8QNH/JSVmnzTUIRV0UZO0R+UTIoB2S4MwkPLLkXBqGHkVlybxHS2+JMvFGKaOq+vW0NF+wjUyTS6MlXUzLI5uGMA105vS2TGcGHO/NhB6/c/UVxdRMH1I1wY0Hi8biCGriGlwZrVK1FKCZWyiGnAOp8IYya38WXjlXTdvMe2niE0Ngd/QTb+ghwXBgSN27LZ8kUAUxq8Wf86sVisx3tX2rDOyAoEmDG7g0UzdQrLPeRZWQyd6OuGQXh4dV0/Tpw00XUdKQ1WrVzRK1DasM4ODVRUECgPkGcZF2A0wMPcZ/zohoGh6UjpZfWq17pe3+tI+8eIaZoseEFQ/4qRxDwwX8MrTXTdwDR1DN3gnbfqOXPuXNqgjGBKKZGfmxuvuG4U987T0HUd3ZBk+bwYXh1D01m7dnXy3ExAGcHAeRqYpkTTJKZpoHsNTkSjbN++rU9AGcMAzGwf7779dvJzX2G6RtowpZR4cenSvnZ0i//f31B/NS7D0o0/AYDZ1IqRUCINAAAAAElFTkSuQmCC" transform="matrix(1, 0, 0, 1, 0, 0)"/>[/HTML]

The important part is the "xlink:href="data:image/png;base64,...".

Questions:
  • Is my concept clear? Is it feasible?

  • How to avoid that if I have to use Internet Explorer?

  • The URL to the PictureMarkerSymbol is part of the LayerDefinition. How can I say to the JS-API that it has to use the URL not the imageData?


If I do a test by simply creating a featureLayer from the URL of this service, it also works in IE. So internally the JS-API has some algorithm to use the URL instead of the imageData.

How can I achive that?

Thanks for any answer. I hope, I made my topic clear... 😉
Axel
0 Kudos
4 Replies
AxelSchaefer
Emerging Contributor
Attached is the example html page.
No warranty. 😄
0 Kudos
KellyHutchins
Esri Frequent Contributor
It looks like you'll need to specify the url to the symbol for this to work in IE 8. If the url property doesn't contain http:// it assumes that the location is relative.

"symbol": {
                "type": "esriPMS",
                "url": "http://somename/somelocation/reddot.png",
                "imageData": "iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oGGBcGLvZ5AIUAAATDSURBVFjD3Zg/aBt3FMe/v9+d7iSfUnNClAolFWnsRaF4LKU2HrK4hJYMKUQiJRRClnbKEE8Z2s1Dh9Bkryk+OoQshZAlhGIPaUpxlIDbRgqOIlSZoNxhx2fpTr8/HXynKL.........

0 Kudos
KellyHutchins
Esri Frequent Contributor
On a related note its not necessary to specify all the values for the layer definition. Here's a simple layer definition that worked for me in your test application.

    var mylayerDefinition = {
          "geometryType": "esriGeometryPoint",
          "drawingInfo": {
            "renderer": {
              "type": "simple",
              "symbol": {
                "type": "esriPMS",
                "url": "reddot.png",
                "imageData": "iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9oGGBcGLvZ5AIUAAATDSURBVFjD3Zg/aBt3FMe/v9+d7iSfUnNClAolFWnsRaF4LKU2HrK4hJYMKUQiJRRClnbKEE8Z2s1Dh9Bkryk+OoQshZAlhGIPaUpxlIDbRgqOIlSZoNxhx2fpTr8/HXynKLXTnGQr/fPgkE7ip/vovff7vvd7REqJfswpFpMAJgFMABgLrt2sElwlAEuXT1mb4RcXP371c0hUMKdYfAvAGQAzGMxuAJi/fMpa2xewHUCaBppKQclmQVMpkNHRXdfJ9XUI2wav1yFsG/D9FwBNy1obGMwpFicBzAJIQtOgZDJQ83kQw+jLVdJ1wVZWwBuNEHATwJxpWUt9gznF4ucATgKAkssNBPRSwGo1/OiqaVlXIoM5xeJsGLrYxASU8XHsp/FyGZ1SqRta07LmXgnW9ZSmQZ+aAjFNDMOk48BbXAxDu8NzdJecOglgqFAAQEwT+tRUeHsyePZOsGD3zYbhGyZUL1xsYiK8nQ0YdnjsDICkksvte079nSnj41ByOQBIBgzPwQLSGWga1Hwer9vUfB7QNACYCb1Ge7wFJZPZsyQMFFLDgJLJ9EYOxC4UkgB+gKZBP3asfzAhCACAse1XVd3e5pTKfjXOu3kz3KUfqUFB3i4v/UAJQcAYla2WIl1XlZ5HAYDouiCGwUgiwaGqIiogMQzQVApibQ0AJtWgS4CSzfYFJT1PkY6jiWYz7t+5M8qr1Th8H/TgwbY+Pb1O0+k2MU2f6DqPCqdksyHYhBq2LTSVig7GGJWOo7FK5Y3VhYVDP3U6I+/HYuSxELjZaMj37t7d+rBQqKn5/AZJpz1oGo/ysz0MYzQEe1mXsKu3Wi1FNJvx3xcWDmVzOePTS5fIOxcu4IPjx3EhmSRLvm98b1mHRLMZl62W0s3DV4XzOcMYHbAYq/7t26M/et5IolCAePIEfHUVvFaDKyWyioLvWq2R9vXro9J11YEkpO8VjBHpeZRVKvF3YzHCHz6E2NgAr9XAy2U8ZgwtKdEUgjx59Cie8zwKxgg0TQ4XLDTfx5oQ6Ny/D9Fsom3b+EMIVDlHhTE0hQDvs21/aRGP9ldUSXRdKEeOtG95nmw/eICnT5/iAWP4tdPBPcZwjzFsCSEz2Wyb6LroattQwbY1h+nT0+uTmrb1tevilwDo504HtzwPq5zj7MjIVvzEiXViGGxQj1XCHj3aCipJIsFpOt3+pFCovUmp++WzZ/Ib18W3W1v4jTH5WSLhfnX6dI2m022SSETWsR6GihqAjQnbhhJVMlRVENP0Y0ePbnxx/vzDs9eujdYbjTgD8HYq1U4UCl2BhaqKyLpt2y+AlQDM8HodyuHD0b2m65yk0x4xDDZy7lx7bI8lCQB4vR6+LakAlgDMCtuGdN3o9ZJSCU3jRFUFOXCgsx9FvMdjS9S0rE0AN+D7YCsrA2QplQGkgKaJ7n2/8riyEnYWN0zL2gx35TwA8EYD0nVfez8mXXf7zNnDQgEgOBUP7rU9Wmd5uddba3/VsXkAm7xaBS+XXxsUL5fDVmcTwJUdAhuQzgFAp1SCdJzhh9Bxeg++c0G+71T+YJZwFQC8xcWhwnUPvM9HBUv/zRHBsIcqneXlMKf6H6r8q8dQQx7cXelN9P/XqPOfGg7/CVtbtVwfC2pGAAAAAElFTkSuQmCC",
                "contentType": "image/png",
                "width": 15,
                "height": 15
              }
            }
          },
          "fields": [{
            "name": "name",
            "type": "esriFieldTypeString",
            "alias": "Name",
            "length": 50
          }]
        };

0 Kudos
AxelSchaefer
Emerging Contributor
Kelly. Thanks! Wonderful! That did it!

The solution then is easy, as you've described in your first posting: Adjust the url property of the symbol to the full URL and IE will use that URL definition for the rendering. That will do it. Also thanks for your second post for shorten the layer-definition. I will customize the whole layerDefinition in one way. 🙂

All in all I think that this is a cool concept of drawing graphics on the graphics layer without dealing with the symbolization rules. I'll test it with some more sophisticated services and data.

Best regards,
Axel

p.s.: to complete the whole thing, a short explanation what I'm doing. I'm uploading a XML and show it in the JS-client. Because some have asked how to do it, here's my way, based on ASPX and JS-API.


  1. Create an ASPX page (.NET 3.5) and put your JS-Client in it.


  2. Put a form (runat sever) and an asp:ScriptManager in it.


  3. Put an AsyncFileUpload on it. It's part of the AJAX Control Toolkit that is shipped with the AGS 10 (i guess at least: ADF, maybe also Server) installation. This AsyncFileUpload control is a bit clumsy but it avoids a page-refresh after uploading. Haven't tested it with a standard asp File Upload in an iframe.


  4. Put an asp:TextBox in the page, multiline. This will act as a container for communication between ASPX backend and JS frontend.


  5. Put a dijit.form.Button below that with the onClick event: showOnMap(); This method will grab the content of the TextBox (dojo.byId("TextBox1")) as the JSON FeatureSet (created below) and fill the myFeatureSet variable (see previous post) with it.


  6. In the Default.aspx.cs write the AsyncFileUpload1_UploadedComplete method. Grab the contents of your uploaded file, parse it and create the JSON FeatureSet. Push it back into the text-box with:


  7. ScriptManager.RegisterClientScriptBlock(AsyncFileUpload1, AsyncFileUpload1.GetType(), "text", "top.document.getElementById('TextBox1').value='" + json + "';",
      true);


    Take care that the text-box doesn't understand "\r\n" or System.Environment.NewLine. So avoid new lines when you create your JSON. You can choose another way to put the JSON to the client,  I tried to give it directly to my showOnMap() method, but it didn't find my GraphicsLayer. With this text-box you can also shortcut for debugging and paste the JSON directly. 😉

That's in short all you have to do.
0 Kudos