Adding a Print Extent Indicator to JavaScript Print Dijit

5177
7
Jump to solution
03-16-2016 12:17 PM
SBerg_VHB
Occasional Contributor

Anyone have suggestions on how to go about calculating and adding an indicator of the actual map extent that a print dijit's current settings and templates would result in?  Assuming you know the ratio of the template's target data frame you can draw a div on top of the map with that ratio but how best to tie to the extent that the print task is going to send or use on the server side?  If you could intercept the map extent being passed in the print task, you could explicitly set the map extent as calculated under the indicator div's screen coordinates but that does not seem accessible.

Thanks for any ideas.

Sam

1 Solution

Accepted Solutions
BillDaigle
Occasional Contributor III

Something like this? FWP Data Review

To do so, we put the dimension in an object:

  this.templateInfos = [{
          'name': "Landscape - Letter",
          'dims': {
            'width': 10.2,
            'height': 6.1866
          }
        }, {
          'name': "Landscape - 17 x 11",
          'dims': {
            'width': 16,
            'height': 8.05
          }
        }, {
          'name': "Map Only - 8 x 8",
          'dims': {
            'width': 8,
            'height': 8
          }
        }];

Then use the following function to update the graphic each time the select is changed.

  _updatePrintArea: function(val) {

        var _this = this;
        if (val == " ") {
          return;
        }

        this.printLayoutGraphicLayer.clear();

        var layoutDims = null;
        array.forEach(this.templateInfos, function(templateInfo) {
          if (val == templateInfo.name) {
            layoutDims = templateInfo.dims;
          }
        });

        var screenPolygon = new Polygon();
        var cntrPnt = screenUtils.toScreenGeometry(this.map.extent, this.map.width, this.map.height, this.map.extent.getCenter());
        //add the outside of the polygon as a ring
        var dpi = 96;
        var outerRingOffset = dpi * 10;
        var yOffset = dpi * layoutDims.height / 2;
        var xOffset = dpi * layoutDims.width / 2;
        screenPolygon.addRing([
          [cntrPnt.x + (xOffset + outerRingOffset), cntrPnt.y + (yOffset + outerRingOffset)],
          [cntrPnt.x + (xOffset + outerRingOffset), cntrPnt.y - (yOffset + outerRingOffset)],
          [cntrPnt.x - (xOffset + outerRingOffset), cntrPnt.y - (yOffset + outerRingOffset)],
          [cntrPnt.x - (xOffset + outerRingOffset), cntrPnt.y + (yOffset + outerRingOffset)],
          [cntrPnt.x + (xOffset + outerRingOffset), cntrPnt.y + (yOffset + outerRingOffset)]
        ]);

        //add the data frame as an inner ring
        screenPolygon.addRing([
          [cntrPnt.x + xOffset, cntrPnt.y + yOffset],
          [cntrPnt.x + xOffset, cntrPnt.y - yOffset],
          [cntrPnt.x - xOffset, cntrPnt.y - yOffset],
          [cntrPnt.x - xOffset, cntrPnt.y + yOffset],
          [cntrPnt.x + xOffset, cntrPnt.y + yOffset]
        ]);

        function getMapGeom(screenGeom) {
          return screenUtils.toMapGeometry(_this.map.extent, _this.map.width, _this.map.height, screenGeom);
        }

        //convert the polygon from screen coordinates to web merc
        var mapPoly = getMapGeom(screenPolygon);

        //add the polygon to the map
        this.printLayoutGraphicLayer.add(new Graphic(mapPoly, this.symbols.polygon));

        //add labels to the map
        var symbolLabel1 = new TextSymbol("Outside Print Area").setColor(new Color([200, 200, 200])).setAlign(TextSymbol.ALIGN_MIDDLE).setFont(new Font("12pt", Font.STYLE_NORMAL, Font.VARIANT_NORMAL, Font.WEIGHT_BOLD, "Arial"));
        var symbolLabel2 = new TextSymbol("Outside Print Area").setAngle(90).setColor(new Color([200, 200, 200])).setAlign(TextSymbol.ALIGN_MIDDLE).setFont(new Font("12pt", Font.STYLE_NORMAL, Font.VARIANT_NORMAL, Font.WEIGHT_BOLD, "Arial"));
        var symbolLabel3 = new TextSymbol("Outside Print Area").setAngle(-90).setColor(new Color([200, 200, 200])).setAlign(TextSymbol.ALIGN_MIDDLE).setFont(new Font("12pt", Font.STYLE_NORMAL, Font.VARIANT_NORMAL, Font.WEIGHT_BOLD, "Arial"));
        this.printLayoutGraphicLayer.add(new Graphic(getMapGeom(cntrPnt.offset(0, yOffset + 0.2 * dpi)), symbolLabel1));
        this.printLayoutGraphicLayer.add(new Graphic(getMapGeom(cntrPnt.offset(0, -1 * (yOffset + 0.1 * dpi))), symbolLabel1));
        this.printLayoutGraphicLayer.add(new Graphic(getMapGeom(cntrPnt.offset(xOffset + 0.1 * dpi, 0)), symbolLabel2));
        this.printLayoutGraphicLayer.add(new Graphic(getMapGeom(cntrPnt.offset(-1 * (xOffset + 0.1 * dpi), 0)), symbolLabel3));

        if (this.extentChangeHandler) {
          this.extentChangeHandler.remove();
        }

        this.extentChangeHandler = this.map.on('extent-change', function() {
          _this._updatePrintArea(val);
        });


      }

View solution in original post

7 Replies
BillDaigle
Occasional Contributor III

Something like this? FWP Data Review

To do so, we put the dimension in an object:

  this.templateInfos = [{
          'name': "Landscape - Letter",
          'dims': {
            'width': 10.2,
            'height': 6.1866
          }
        }, {
          'name': "Landscape - 17 x 11",
          'dims': {
            'width': 16,
            'height': 8.05
          }
        }, {
          'name': "Map Only - 8 x 8",
          'dims': {
            'width': 8,
            'height': 8
          }
        }];

Then use the following function to update the graphic each time the select is changed.

  _updatePrintArea: function(val) {

        var _this = this;
        if (val == " ") {
          return;
        }

        this.printLayoutGraphicLayer.clear();

        var layoutDims = null;
        array.forEach(this.templateInfos, function(templateInfo) {
          if (val == templateInfo.name) {
            layoutDims = templateInfo.dims;
          }
        });

        var screenPolygon = new Polygon();
        var cntrPnt = screenUtils.toScreenGeometry(this.map.extent, this.map.width, this.map.height, this.map.extent.getCenter());
        //add the outside of the polygon as a ring
        var dpi = 96;
        var outerRingOffset = dpi * 10;
        var yOffset = dpi * layoutDims.height / 2;
        var xOffset = dpi * layoutDims.width / 2;
        screenPolygon.addRing([
          [cntrPnt.x + (xOffset + outerRingOffset), cntrPnt.y + (yOffset + outerRingOffset)],
          [cntrPnt.x + (xOffset + outerRingOffset), cntrPnt.y - (yOffset + outerRingOffset)],
          [cntrPnt.x - (xOffset + outerRingOffset), cntrPnt.y - (yOffset + outerRingOffset)],
          [cntrPnt.x - (xOffset + outerRingOffset), cntrPnt.y + (yOffset + outerRingOffset)],
          [cntrPnt.x + (xOffset + outerRingOffset), cntrPnt.y + (yOffset + outerRingOffset)]
        ]);

        //add the data frame as an inner ring
        screenPolygon.addRing([
          [cntrPnt.x + xOffset, cntrPnt.y + yOffset],
          [cntrPnt.x + xOffset, cntrPnt.y - yOffset],
          [cntrPnt.x - xOffset, cntrPnt.y - yOffset],
          [cntrPnt.x - xOffset, cntrPnt.y + yOffset],
          [cntrPnt.x + xOffset, cntrPnt.y + yOffset]
        ]);

        function getMapGeom(screenGeom) {
          return screenUtils.toMapGeometry(_this.map.extent, _this.map.width, _this.map.height, screenGeom);
        }

        //convert the polygon from screen coordinates to web merc
        var mapPoly = getMapGeom(screenPolygon);

        //add the polygon to the map
        this.printLayoutGraphicLayer.add(new Graphic(mapPoly, this.symbols.polygon));

        //add labels to the map
        var symbolLabel1 = new TextSymbol("Outside Print Area").setColor(new Color([200, 200, 200])).setAlign(TextSymbol.ALIGN_MIDDLE).setFont(new Font("12pt", Font.STYLE_NORMAL, Font.VARIANT_NORMAL, Font.WEIGHT_BOLD, "Arial"));
        var symbolLabel2 = new TextSymbol("Outside Print Area").setAngle(90).setColor(new Color([200, 200, 200])).setAlign(TextSymbol.ALIGN_MIDDLE).setFont(new Font("12pt", Font.STYLE_NORMAL, Font.VARIANT_NORMAL, Font.WEIGHT_BOLD, "Arial"));
        var symbolLabel3 = new TextSymbol("Outside Print Area").setAngle(-90).setColor(new Color([200, 200, 200])).setAlign(TextSymbol.ALIGN_MIDDLE).setFont(new Font("12pt", Font.STYLE_NORMAL, Font.VARIANT_NORMAL, Font.WEIGHT_BOLD, "Arial"));
        this.printLayoutGraphicLayer.add(new Graphic(getMapGeom(cntrPnt.offset(0, yOffset + 0.2 * dpi)), symbolLabel1));
        this.printLayoutGraphicLayer.add(new Graphic(getMapGeom(cntrPnt.offset(0, -1 * (yOffset + 0.1 * dpi))), symbolLabel1));
        this.printLayoutGraphicLayer.add(new Graphic(getMapGeom(cntrPnt.offset(xOffset + 0.1 * dpi, 0)), symbolLabel2));
        this.printLayoutGraphicLayer.add(new Graphic(getMapGeom(cntrPnt.offset(-1 * (xOffset + 0.1 * dpi), 0)), symbolLabel3));

        if (this.extentChangeHandler) {
          this.extentChangeHandler.remove();
        }

        this.extentChangeHandler = this.map.on('extent-change', function() {
          _this._updatePrintArea(val);
        });


      }
SurendranNeelakantan
New Contributor III

Hi Bill , This is  a great tool , That I was using successfully for a while.  Recently we upgraded our ESRI  Jvascript API to 4.7.  I am having difficulty to  upgrade this part , especially ScreenUtils is not available yet. Did you upgraded this tool ? It would be great  if you could share some spinet to that helps me to upgrade my code.

Thanks!

Surendran

0 Kudos
SBerg_VHB
Occasional Contributor

Great idea, Bill, thanks.

I was going to try and calculate the print extent and send to the print job explicilty, but it makes good sense to just show the indicator of what is going to be the calculated extent.

Your code works well and I appreciate the post.

Cheers,

Sam

0 Kudos
BillDaigle
Occasional Contributor III

Hi Sam,

The extent will get passed if you set the preserveScale parameter to false:  PrintTemplate | API Reference | ArcGIS API for JavaScript

Personally, I find it more intuitive to lock down the scale so the map doesn't zoom in or out, which can change the image  significantly if you have scale dependencies set.

RogerF
by
Occasional Contributor

Hi Bill, 

Great tool. Thanks for posting the code. A quick question. Once you draw graphics on the map showing the print area, how to do you pass that spatial extent to print task ?

Would you mind posting the code sample for that ?

0 Kudos
BillDaigle
Occasional Contributor III

Hi Roger,

Here is the function that use when the user click the "Go" button.  Since the scale is preserved, I don't actually pass the extent directly.

     _onClickPrint: function() {

        var _this = this;
        if (this.printForm.validate() == false) {
          return;
        }


        if (this._txtTitle.value !== "") {
          this.printTitle = this._txtTitle.value;
        }
        var standby = new Standby({
          target: this.containerNode.parentNode
        });
        document.body.appendChild(standby.domNode);
        standby.startup();

        standby.show();

        function getLegendInfos() {
          var legLayers = 0 || [];
          array.forEach(_this.main.map.layerIds, function(layerId) {
            lyr = _this.main.map.getLayer(layerId);
            if (!lyr._basemapGalleryLayerType && lyr.visibleLayers && lyr.visibleLayers.length > 0 && lyr.id.indexOf('basemapRef_') != 0) {
              var legendLayer = new LegendLayer();
              legendLayer.layerId = lyr.id;
              legendLayer.subLayerIds = [];
              array.forEach(lyr.layerInfos, function(layerInfos) {
                legendLayer.subLayerIds.push(layerInfos.id);
              });
              legLayers.push(legendLayer);
            }
          });
          return legLayers;
        };

        var layoutOptions = {
          "titleText": this.printTitle,
          "customTextElements": [{
            "printText": this.main.printDisclaimer
          }],
          legendLayers: getLegendInfos()
        };
        //  console.debug(this._layout.value,this._format.value,this._geoRef,true)
        this.printParams.template = {
          layout: this._layout.value,
          format: this._format.value,
          Georef_info: this._geoRef,
          preserveScale: true
        };
        this.printParams.template.layoutOptions = layoutOptions;
        this.printParams.extraParameters = {
          Georef_info: this._geoRef.value,
          outputFormat: this._format.value,
          Second_Page_Content: this.main.printSecondPageContent
        };

        this._resetForm();

        //Temporarily reset the default timeout
        var originalTimeout =  esriConfig.defaults.io.timeout;
        esriConfig.defaults.io.timeout = 180000;

        //run the print request
        var deferred = this.printTask.execute(this.printParams);

        //handle the result
        deferred.then(function(result) {
          window.open(result.url);
          standby.hide();
        }, function(err) {
          standby.hide();
          _this.main.logMsg('error', 'Print error', err);
          alert(err + " error caused the print operation to fail.  Please try again.");
        });

        //Change the timeout back
        esriConfig.defaults.io.timeout = originalTimeout;


      }
RogerF
by
Occasional Contributor

Thank you Bill. I will try that.

0 Kudos