I have a point feature layer published as a FeatureService to ArcGIS Server. On the client side I use "esri/renderers/HeatmapRenderer" to render it as a heat map. And then I try to use ArcGIS Server default printing tool to print the heatmap, but I get an error message as below:
"Error executing tool.: Layer "graphicsLayer2": Unsupported 'type' in renderer: heatmap.
Failed to execute (Export Web Map).
Failed to execute (Export Web Map Task)."
I also try to create the heatmap using Patrick Weid's heatmap.js (heatmap.js | Dynamic Heatmaps for the Web). And again, I can't print it with ArcGIS Server's printing tool.
I am wondering whether there is anyone out there who has successfully printed out a heatmap.
Thanks,
Xuejin
Solved! Go to Solution.
Hi Xuejin,
In case you're still looking for a solution - I just had the same problem and combined the Heatmap and Print sampels from the JS API Resource Center, and it works. Here's the code:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"> <title></title> <link rel="stylesheet" href="http://js.arcgis.com/3.13/dijit/themes/nihilo/nihilo.css"> <link rel="stylesheet" href="http://js.arcgis.com/3.13/esri/css/esri.css"> <style> html, body { height: 100%; width: 100%; margin: 0; padding: 0; } body{ background-color: #fff; overflow:hidden; font-family: sans-serif; } label { display: inline-block; padding: 5px 5px 0 5px; font-weight: 400; font-size: 12pt; } .button { width: 100%; margin: 3px auto; text-align: center; } #header { padding-top: 4px; padding-right: 15px; color: #444; font-size:16pt; text-align:right;font-weight:bold; height:55px; background: #fff; border-bottom: 1px solid #444; } #subheader { font-size:small; color: #444; text-align:right; padding-right:20px; } #rightPane{ margin: 0; padding: 10px; background-color: #fff; color: #421b14; width: 180px; } .ds { background: #000; overflow: hidden; position: absolute; z-index: 2; } #ds-h div { width: 100%; } #ds-l div, #ds-r div { height: 100%; } #ds-r div { right: 0; } #ds .o1 { filter: alpha(opacity=10); opacity: .1; } #ds .o2 { filter: alpha(opacity=8); opacity: .08; } #ds .o3 { filter: alpha(opacity=6); opacity: .06; } #ds .o4 { filter: alpha(opacity=4); opacity: .04; } #ds .o5 { filter: alpha(opacity=2); opacity: .02; } #ds .h1 { height: 1px; } #ds .h2 { height: 2px; } #ds .h3 { height: 3px; } #ds .h4 { height: 4px; } #ds .h5 { height: 5px; } #ds .v1 { width: 1px; } #ds .v2 { width: 2px; } #ds .v3 { width: 3px; } #ds .v4 { width: 4px; } #ds .v5 { width: 5px; } /* make all dijit buttons the same width */ .dijitButton .dijitButtonNode, #drawingWrapper, #printButton { width: 160px; } .esriPrint { padding: 0; } </style> <script src="http://js.arcgis.com/3.13/"></script> <script> var app = {}; app.map = null; app.toolbar = null; app.tool = null; app.symbols = null; app.printer = null; require([ "esri/map", "esri/toolbars/draw", "esri/dijit/Print", "esri/layers/ArcGISTiledMapServiceLayer", "esri/layers/ArcGISDynamicMapServiceLayer", "esri/layers/LayerDrawingOptions", "esri/symbols/SimpleMarkerSymbol", "esri/symbols/SimpleLineSymbol", "esri/symbols/SimpleFillSymbol", "esri/graphic", "esri/renderers/ClassBreaksRenderer", "esri/config", "dojo/_base/array", "esri/Color", "dojo/parser", "dojo/query", "dojo/dom", "dojo/dom-construct", "dijit/form/CheckBox", "dijit/form/Button", "esri/InfoTemplate", "esri/layers/FeatureLayer", "esri/map", "esri/renderers/HeatmapRenderer", "dijit/layout/BorderContainer", "dijit/layout/ContentPane", "dojo/domReady!" ], function( Map, Draw, Print, ArcGISTiledMapServiceLayer, ArcGISDynamicMapServiceLayer, LayerDrawingOptions, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, Graphic, ClassBreaksRenderer, esriConfig, arrayUtils, Color, parser, query, dom, domConstruct, CheckBox, Button, InfoTemplate, FeatureLayer, Map, HeatmapRenderer ) { // -------------------------------------------------------------------- // Formatting functions for attribute values in the InfoWindow // Data is not what you expect, turn your dirty data into // readable stuff in the infowindow // -------------------------------------------------------------------- formatFatalities = function (value, key, data){ var result = value > 1 ? value + " people " : value + " person "; return result; } formatGender = function (value, key, data){ var lookup = {1: "male", 2: "female", 8: "unknown", 9: "unknown"}; return lookup[value]; } formatConditions = function (value, key, data){ var lookup = {0: "No Additional Atmospheric Conditions", 1: "Clear", 2: "Rain", 3: "Sleet, Hail (Freezing Rain or Drizzle)", 4: "Snow", 5: "Fog, Smog, Smoke", 6: "Severe Crosswinds", 7: "Blowing Sand, Soil, Dirt", 8: "Other", 10: "Cloudy", 11: "Blowing Snow", 98: "Not Reported", 99: "Unknown"}; if (value !== 1) { return "Road conditions: " + lookup[value] + "<br>"; } } formatWorkZone = function (value, key, data){ var lookup = {0: "None", 1: "Construction", 2: "Maintenance", 3: "Utility", 4: "Work Zone, Type Unknown"}; if (value !== 0) { return "Work Zone: " + lookup[value] + "<br>"; } } formatAlcoholTestResults = function (value, key, data){ // -------------------------------------------------------------------- // The field is a string and we only want values of 8 - 94 since the // California legal limit is 0.08% BAC. If value is between 8 and 94 // then we will report that they were over the legal limit. // -------------------------------------------------------------------- var isMatch = value.match(/\b(?!9[5-9])[0-9][0-9]\b|\b[8-9]{1}\b/m); if (isMatch) { return "Driver was over the legal limit for alcohol"; } } parser.parse(); esriConfig.defaults.io.proxyUrl = "/proxy/"; app.map = new Map("map", { center: [-117.733, 36], zoom: 7 }); app.map.on("load", function() { app.toolbar = new Draw(app.map); app.toolbar.on("draw-end", addToMap); }); // print dijit app.printer = new Print({ map: app.map, url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%2..." }, dom.byId("printButton")); app.printer.startup(); var url = "http://services.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer"; var tiledLayer = new ArcGISTiledMapServiceLayer(url, { "id": "Ocean" }); app.map.addLayer(tiledLayer); var infoContentDesc = "<p>${numfatal:formatFatalities} died when a ${age} year old ${sex:formatGender} was involved in a fatal speeding accident.</p>"; var infoContentDetails = "${atmcond:formatConditions}${conszone:formatWorkZone}${alcres:formatAlcoholTestResults}"; var infoContent = infoContentDesc + infoContentDetails; var infoTemplate = new InfoTemplate("Accident details", infoContent); var serviceURL = "//services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/2012_CA_NHTSA/FeatureServer/0"; var heatmapFeatureLayerOptions = { mode: FeatureLayer.MODE_SNAPSHOT, infoTemplate: infoTemplate, outFields: [ "atmcond", "numfatal", "conszone", "age", "alcres", "sex" ] }; var heatmapFeatureLayer = new FeatureLayer(serviceURL, heatmapFeatureLayerOptions); var heatmapRenderer = new HeatmapRenderer(); heatmapFeatureLayer.setRenderer(heatmapRenderer); app.map.addLayer(heatmapFeatureLayer); // create a check box for each map layer arrayUtils.forEach(["County Population", "Ocean"], function(id) { new CheckBox({ id: "cb_" + id, name: "cb_" + id, checked: true, onChange: function(bool) { bool ? app.map.getLayer(this.id.split("_")[1]).show() : app.map.getLayer(this.id.split("_")[1]).hide(); } }, domConstruct.create("input", { id: "lyr_" + id })).placeAt(dom.byId("layerToggle")); // create a label for the check box var label = domConstruct.create('label', { "for": "cb_" + id, "innerHTML": id }); domConstruct.place(label, dom.byId("layerToggle")); domConstruct.place(domConstruct.create("br"), dom.byId("layerToggle")); }); // set up symbols for the various geometry types app.symbols = {}; app.symbols.point = new SimpleMarkerSymbol("square", 10, new SimpleLineSymbol(), new Color([0, 255, 0, 0.75])); app.symbols.polyline = new SimpleLineSymbol("solid", new Color([255, 128, 0]), 2); app.symbols.polygon = new SimpleFillSymbol().setColor(new Color([255,255,0,0.25])); app.symbols.circle = new SimpleFillSymbol().setColor(new Color([0, 0, 180, 0.25])); // find the divs for buttons query(".drawing").forEach(function(btn) { var button = new Button({ label: btn.innerHTML, onClick: function() { activateTool(this.id); } }, btn); }); function activateTool(type) { app.tool = type.replace("freehand", ""); app.toolbar.activate(type); app.map.hideZoomSlider(); } function addToMap(evt) { app.toolbar.deactivate(); app.map.showZoomSlider(); var graphic = new Graphic(evt.geometry, app.symbols[app.tool]); app.map.graphics.add(graphic); } }); </script> </head> <body class="nihilo"> <div id="mainWindow" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline',gutters:false" style="width: 100%; height: 100%; margin: 0;"> <div id="header" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'"> Print Dijit: Out of the Box Printing for the ArcGIS API for JavaScript <div id="subheader">Requires ArcGIS Server 10.1</div> </div> <div id="map" class="shadow" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"> </div> <div id="rightPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'right'"> <div id="printButton"></div> <hr /> <div id="drawingWrapper"> Add some graphics: <div id="point" class="drawing">Point</div> <div id="freehandpolyline" class="drawing">Freehand Polyline</div> <div id="freehandpolygon" class="drawing">Freehand Polygon</div> <div id="circle" class="drawing">Circle</div> </div> <hr /> <div id="layerToggle"> Toggle Layers: <br /> <!-- checkbox and labels inserted programmatically --> </div> </div> </div> </body> </html>
Hi Xuejin,
In case you're still looking for a solution - I just had the same problem and combined the Heatmap and Print sampels from the JS API Resource Center, and it works. Here's the code:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"> <title></title> <link rel="stylesheet" href="http://js.arcgis.com/3.13/dijit/themes/nihilo/nihilo.css"> <link rel="stylesheet" href="http://js.arcgis.com/3.13/esri/css/esri.css"> <style> html, body { height: 100%; width: 100%; margin: 0; padding: 0; } body{ background-color: #fff; overflow:hidden; font-family: sans-serif; } label { display: inline-block; padding: 5px 5px 0 5px; font-weight: 400; font-size: 12pt; } .button { width: 100%; margin: 3px auto; text-align: center; } #header { padding-top: 4px; padding-right: 15px; color: #444; font-size:16pt; text-align:right;font-weight:bold; height:55px; background: #fff; border-bottom: 1px solid #444; } #subheader { font-size:small; color: #444; text-align:right; padding-right:20px; } #rightPane{ margin: 0; padding: 10px; background-color: #fff; color: #421b14; width: 180px; } .ds { background: #000; overflow: hidden; position: absolute; z-index: 2; } #ds-h div { width: 100%; } #ds-l div, #ds-r div { height: 100%; } #ds-r div { right: 0; } #ds .o1 { filter: alpha(opacity=10); opacity: .1; } #ds .o2 { filter: alpha(opacity=8); opacity: .08; } #ds .o3 { filter: alpha(opacity=6); opacity: .06; } #ds .o4 { filter: alpha(opacity=4); opacity: .04; } #ds .o5 { filter: alpha(opacity=2); opacity: .02; } #ds .h1 { height: 1px; } #ds .h2 { height: 2px; } #ds .h3 { height: 3px; } #ds .h4 { height: 4px; } #ds .h5 { height: 5px; } #ds .v1 { width: 1px; } #ds .v2 { width: 2px; } #ds .v3 { width: 3px; } #ds .v4 { width: 4px; } #ds .v5 { width: 5px; } /* make all dijit buttons the same width */ .dijitButton .dijitButtonNode, #drawingWrapper, #printButton { width: 160px; } .esriPrint { padding: 0; } </style> <script src="http://js.arcgis.com/3.13/"></script> <script> var app = {}; app.map = null; app.toolbar = null; app.tool = null; app.symbols = null; app.printer = null; require([ "esri/map", "esri/toolbars/draw", "esri/dijit/Print", "esri/layers/ArcGISTiledMapServiceLayer", "esri/layers/ArcGISDynamicMapServiceLayer", "esri/layers/LayerDrawingOptions", "esri/symbols/SimpleMarkerSymbol", "esri/symbols/SimpleLineSymbol", "esri/symbols/SimpleFillSymbol", "esri/graphic", "esri/renderers/ClassBreaksRenderer", "esri/config", "dojo/_base/array", "esri/Color", "dojo/parser", "dojo/query", "dojo/dom", "dojo/dom-construct", "dijit/form/CheckBox", "dijit/form/Button", "esri/InfoTemplate", "esri/layers/FeatureLayer", "esri/map", "esri/renderers/HeatmapRenderer", "dijit/layout/BorderContainer", "dijit/layout/ContentPane", "dojo/domReady!" ], function( Map, Draw, Print, ArcGISTiledMapServiceLayer, ArcGISDynamicMapServiceLayer, LayerDrawingOptions, SimpleMarkerSymbol, SimpleLineSymbol, SimpleFillSymbol, Graphic, ClassBreaksRenderer, esriConfig, arrayUtils, Color, parser, query, dom, domConstruct, CheckBox, Button, InfoTemplate, FeatureLayer, Map, HeatmapRenderer ) { // -------------------------------------------------------------------- // Formatting functions for attribute values in the InfoWindow // Data is not what you expect, turn your dirty data into // readable stuff in the infowindow // -------------------------------------------------------------------- formatFatalities = function (value, key, data){ var result = value > 1 ? value + " people " : value + " person "; return result; } formatGender = function (value, key, data){ var lookup = {1: "male", 2: "female", 8: "unknown", 9: "unknown"}; return lookup[value]; } formatConditions = function (value, key, data){ var lookup = {0: "No Additional Atmospheric Conditions", 1: "Clear", 2: "Rain", 3: "Sleet, Hail (Freezing Rain or Drizzle)", 4: "Snow", 5: "Fog, Smog, Smoke", 6: "Severe Crosswinds", 7: "Blowing Sand, Soil, Dirt", 8: "Other", 10: "Cloudy", 11: "Blowing Snow", 98: "Not Reported", 99: "Unknown"}; if (value !== 1) { return "Road conditions: " + lookup[value] + "<br>"; } } formatWorkZone = function (value, key, data){ var lookup = {0: "None", 1: "Construction", 2: "Maintenance", 3: "Utility", 4: "Work Zone, Type Unknown"}; if (value !== 0) { return "Work Zone: " + lookup[value] + "<br>"; } } formatAlcoholTestResults = function (value, key, data){ // -------------------------------------------------------------------- // The field is a string and we only want values of 8 - 94 since the // California legal limit is 0.08% BAC. If value is between 8 and 94 // then we will report that they were over the legal limit. // -------------------------------------------------------------------- var isMatch = value.match(/\b(?!9[5-9])[0-9][0-9]\b|\b[8-9]{1}\b/m); if (isMatch) { return "Driver was over the legal limit for alcohol"; } } parser.parse(); esriConfig.defaults.io.proxyUrl = "/proxy/"; app.map = new Map("map", { center: [-117.733, 36], zoom: 7 }); app.map.on("load", function() { app.toolbar = new Draw(app.map); app.toolbar.on("draw-end", addToMap); }); // print dijit app.printer = new Print({ map: app.map, url: "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%2..." }, dom.byId("printButton")); app.printer.startup(); var url = "http://services.arcgisonline.com/ArcGIS/rest/services/Ocean_Basemap/MapServer"; var tiledLayer = new ArcGISTiledMapServiceLayer(url, { "id": "Ocean" }); app.map.addLayer(tiledLayer); var infoContentDesc = "<p>${numfatal:formatFatalities} died when a ${age} year old ${sex:formatGender} was involved in a fatal speeding accident.</p>"; var infoContentDetails = "${atmcond:formatConditions}${conszone:formatWorkZone}${alcres:formatAlcoholTestResults}"; var infoContent = infoContentDesc + infoContentDetails; var infoTemplate = new InfoTemplate("Accident details", infoContent); var serviceURL = "//services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/2012_CA_NHTSA/FeatureServer/0"; var heatmapFeatureLayerOptions = { mode: FeatureLayer.MODE_SNAPSHOT, infoTemplate: infoTemplate, outFields: [ "atmcond", "numfatal", "conszone", "age", "alcres", "sex" ] }; var heatmapFeatureLayer = new FeatureLayer(serviceURL, heatmapFeatureLayerOptions); var heatmapRenderer = new HeatmapRenderer(); heatmapFeatureLayer.setRenderer(heatmapRenderer); app.map.addLayer(heatmapFeatureLayer); // create a check box for each map layer arrayUtils.forEach(["County Population", "Ocean"], function(id) { new CheckBox({ id: "cb_" + id, name: "cb_" + id, checked: true, onChange: function(bool) { bool ? app.map.getLayer(this.id.split("_")[1]).show() : app.map.getLayer(this.id.split("_")[1]).hide(); } }, domConstruct.create("input", { id: "lyr_" + id })).placeAt(dom.byId("layerToggle")); // create a label for the check box var label = domConstruct.create('label', { "for": "cb_" + id, "innerHTML": id }); domConstruct.place(label, dom.byId("layerToggle")); domConstruct.place(domConstruct.create("br"), dom.byId("layerToggle")); }); // set up symbols for the various geometry types app.symbols = {}; app.symbols.point = new SimpleMarkerSymbol("square", 10, new SimpleLineSymbol(), new Color([0, 255, 0, 0.75])); app.symbols.polyline = new SimpleLineSymbol("solid", new Color([255, 128, 0]), 2); app.symbols.polygon = new SimpleFillSymbol().setColor(new Color([255,255,0,0.25])); app.symbols.circle = new SimpleFillSymbol().setColor(new Color([0, 0, 180, 0.25])); // find the divs for buttons query(".drawing").forEach(function(btn) { var button = new Button({ label: btn.innerHTML, onClick: function() { activateTool(this.id); } }, btn); }); function activateTool(type) { app.tool = type.replace("freehand", ""); app.toolbar.activate(type); app.map.hideZoomSlider(); } function addToMap(evt) { app.toolbar.deactivate(); app.map.showZoomSlider(); var graphic = new Graphic(evt.geometry, app.symbols[app.tool]); app.map.graphics.add(graphic); } }); </script> </head> <body class="nihilo"> <div id="mainWindow" data-dojo-type="dijit/layout/BorderContainer" data-dojo-props="design:'headline',gutters:false" style="width: 100%; height: 100%; margin: 0;"> <div id="header" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'top'"> Print Dijit: Out of the Box Printing for the ArcGIS API for JavaScript <div id="subheader">Requires ArcGIS Server 10.1</div> </div> <div id="map" class="shadow" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'center'"> </div> <div id="rightPane" data-dojo-type="dijit/layout/ContentPane" data-dojo-props="region:'right'"> <div id="printButton"></div> <hr /> <div id="drawingWrapper"> Add some graphics: <div id="point" class="drawing">Point</div> <div id="freehandpolyline" class="drawing">Freehand Polyline</div> <div id="freehandpolygon" class="drawing">Freehand Polygon</div> <div id="circle" class="drawing">Circle</div> </div> <hr /> <div id="layerToggle"> Toggle Layers: <br /> <!-- checkbox and labels inserted programmatically --> </div> </div> </div> </body> </html>
Thanks so much Niklas! Can't believe I didn't see your reply until today.
Yes you are right. It works! I think the newer version of javascript API supports HeatmapRenderer.
Thanks again!
Sincerely,
Xuejin
Glad I could help!
Can anyone help me?
I have created a heat map using heatmapRendrerer using the next sample:
Samples | ArcGIS API for JavaScript
The renderer apply it to a featureLayer that in turn get a MapService . My question is:
Is there way to apply this renderer instead of using a FeatureLayer use a ArcGISDynamicMapServiceLayer ?
Thanks.