PrintTemplate issue - Legend Missing - Could Unique Value Expressions be the cause?

865
8
Jump to solution
02-14-2023 02:21 PM
AndrewMurdoch1
Occasional Contributor II

Good Day

I have a weird issue where my PrintTask outputs are missing legend, sometimes, but not others, and I can't find a pattern as to why.  I have a unique value render setting with ~160 different values in it, and on most of the maps I use a valueExpression to set the renderer. 

If I take two maps which use the same valueExpression, literally the same one, and compare them, one will generate with legends, and the other won't.

Map 1:

AndrewMurdoch1_0-1676413232308.png

Map 2:

AndrewMurdoch1_1-1676413298124.png

 

The valueExpression: When($feature.aType == 3 && $feature.ci > -10 && $feature.ci <= 40, 'condition_3_Crititcal',$feature.aType == 3 && $feature.ci > 40 && $feature.ci <= 50, 'condition_3_Poor',$feature.aType == 3 && $feature.ci > 50 && $feature.ci <= 65, 'condition_3_Fair',$feature.aType == 3 && $feature.ci > 65 && $feature.ci <= 90, 'condition_3_Good',$feature.aType == 3 && $feature.ci > 90 && $feature.ci <= 99, 'condition_3_Excellent',$feature.aType == 3 && $feature.ci > 99 && $feature.ci <= 100, 'condition_3_Perfect',$feature.aType == 3 && $feature.ci > -10 && $feature.ci <= 0, 'condition_3_Not Defined','condition_Not Defined')

That is the valueExpression shared by both maps, the first will generate a legend, the second won't.  This is my print function:

 

  public printMap(): void {
		const titleText = 'Map: ';

/*			let layerLegend = new LegendLayer();
		let layerIds = [];
		this._view.map.layers.forEach((layer) => {
			layerIds.push(layer.id);
		})

		layerLegend.layerId = "layer1";
		layerLegend.subLayerIds = layerIds;
		legendLayers: [layerLegend],

		*/


		const template = new PrintTemplate({
			format: 'pdf',
			layout: 'a4-landscape',
			layoutOptions: {
				authorText: 'Blah',
				titleText
			},
		});

		const params = new PrintParameters({
			view: this._view,
			template,
		});

		//
		// NOTE: Start the print progress spinner
		//
		this.printProgress = true;
		const printURL = 'https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task';
		PrintTask.execute(printURL, params).then((result) => {
			//
			// NOTE: Stop the spinner and open the print output
			//       into a new tab.
			//
			this.printProgress = false;
			this.forceChange();
			window.open(result.url);
		}, () => {
			this.alert.errorDialog('Print Error', 'Please try again or contact support!');
			this.printProgress = false;
			this.forceChange();
		});
  }

 


Is there any reason for this behaviour? I'm I missing something in the PrintTemplate or PrintParameters? 

On a strange note, I don't use a valueExpression, I always get a legend on the print output:

AndrewMurdoch1_0-1676412866969.png

I suspect the problem has to do with the use of the valueExpression, so is there a way to pass my legend / layer information directly to the print task?

Thanks

0 Kudos
1 Solution

Accepted Solutions
AndrewMurdoch1
Occasional Contributor II

Good Day

I found a solution!  I was previous performing a featureEffect query to show and hide layers, setting excluded layers to opacity 0%.  This was working great until yesterday when we noticed I could still interact with the features (my fault, I should have thought about that!). 

I decided to move from the featureEffect query to the layerView filter query, and now all PrintTasks are showing up with legends intact.  It seems for some odd reason that the “featureEffect” was causing the problem.

Hopefully this can help others in the future!

Thanks for your help.

View solution in original post

8 Replies
Noah-Sager
Esri Regular Contributor

Hello @AndrewMurdoch1, thanks for posting your question here. A couple questions: which version of the API are you using? And is there a difference between the layer types when the legend items print vs. doesn't print?

0 Kudos
AndrewMurdoch1
Occasional Contributor II

Good Day

API Version 4.25.5

    "@arcgis/core": "4.25.5",
    "@esri/arcgis-rest-auth": "3.6.0",
    "@esri/arcgis-rest-feature-layer": "3.6.0",
    "@esri/arcgis-rest-portal": "3.6.0",
    "@esri/arcgis-rest-request": "3.6.0",
    "@esri/arcgis-rest-types": "3.6.0",
    "@esri/calcite-components": "1.0.2",


All the layers are Feature Layers, here is the way they're set up:

  private buildFeatureSettings(geometryType: string, data: any, metaLayer: boolean = false): any {
    const layerLabelClass = new LabelClass({
      labelExpressionInfo: {expression: '$feature.label'},
      symbol: {
        type: 'text',
        color: 'black',
        haloSize: 1,
        haloColor: 'white'
      }
    });

    const renderSetting = this.buildRenderSettingForLayer(geometryType);
    return {
      fields: metaLayer ? this._metaFields : this._fields,
      geometryType: geometryType,
      globalIdField: 'assetSectionId',
      id: metaLayer ? `meta-${data[0].attributes.layerId}` : this.generateUniqSerial(),
      labelingInfo: [layerLabelClass],
      objectIdField: 'ObjectID',
      outFields: ['*'],
      renderer: renderSetting,
      source: data,
      title: '',
      visible: true
    }
  }


“renderSetting” is the same for all layers, it's ~160 Unique Value Render Settings.  One thing I have noticed is that the layers which don't use “valueExpressions” are always showing up, I only see this odd behaviour when I use “valueExpressions”, but it's not constant.

Any help would be greatly appreciated 🙂

Thanks

0 Kudos
AndrewMurdoch1
Occasional Contributor II

If it matters, this is buildRenderSetting

  private buildRenderSettingForLayer(geometryType: string = 'polyline'): UniqueValueRenderer {
    let renderSetting;

    if (this.gisFlag) {
      if (geometryType === 'point' && this.tabIndex === 0) {
        // NOTE: The first tab in the GIS Page is a "Picture Marker"
        renderSetting = this.render.getUniqueRenderSetting(`picture-point`);
      } else {
        // NOTE: Handle lines / polygons
        renderSetting = this.render.getUniqueRenderSetting(geometryType);
      }
    } else {
      // NOTE: Handle lines / polygons
      renderSetting = this.render.getUniqueRenderSetting(geometryType);
    }

    if (this.gisFlag) {
      const gisFieldInformation = this.whichGISField();

      renderSetting.field = gisFieldInformation.field;
      renderSetting.valueExpression = null;

      if (gisFieldInformation.valueExpression !== '') {
        renderSetting.field = '';
        renderSetting.valueExpression = gisFieldInformation.valueExpression;

        this.hostLayerState = this.render.getLegend(gisFieldInformation.legendType);
        this.hostLayerState.forEach((layerState) => {
          layerState.field = gisFieldInformation.legendField;
        })
      }
    } else if (this.performance) {
      if (!this._year) {
        this._year = 2022;
      }

      renderSetting.field = '';
      const valueExpression =
        this.render.getValueExpression('CONDITION');

      renderSetting.valueExpression =
        valueExpression.replaceAll('FIELD_REPLACE_TEXT', `$feature.F${this._year}`);
    } else if (this._capitalPlan || this._alignment) {
      renderSetting.field = `F${this._year}`;
      renderSetting.valueExpression = '';
    }

    console.log('Render Setting - Build Render Setting');
    console.log(_.cloneDeep(renderSetting));
    return renderSetting;
  }
0 Kudos
Noah-Sager
Esri Regular Contributor

Hmm, can you check the network traffic and compare the two print requests? Open the developer tools in the browser of choice, and look at the execute request when printing and compare the two payloads. My hunch is that there will be a difference, but even if there's not, it would still be helpful to know.

0 Kudos
AndrewMurdoch1
Occasional Contributor II

Thanks for the suggestion, I'm kind of baffled as to why I didn't think of that myself.  The “featureCollection” object is missing when the legend isn't present.  When I don't have the “featureCollection”, I have “imageData”, and I think that's what is causing the problem.

Should I be adding in LegendLayers into the Print Parameters?  https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-support-LegendLayer.html

If so, what do I pass for layerId and subLayerId?  I would assume I get the layerId with:

const legendLayers = []
this._view.map.layers.forEach((layer) => {
    let legendLayer = new LegendLayer();
    legendLayer.layerId = layer.id;
    legendLayer.subLayerId = [] // NOTE: I don't know what to pass for this
});

 
I already to do this, but I keep getting three boxes, Red, Green and Blue showing up, which I think it due to incorrectly assembling the legend layers array.

If run a featureEffect filter, or manually replace the render setting on a feature layer with layer.renderer = newRenderSetting, will that cause an issue? 

Thanks!

0 Kudos
AndrewMurdoch1
Occasional Contributor II

Good Day

I found a solution!  I was previous performing a featureEffect query to show and hide layers, setting excluded layers to opacity 0%.  This was working great until yesterday when we noticed I could still interact with the features (my fault, I should have thought about that!). 

I decided to move from the featureEffect query to the layerView filter query, and now all PrintTasks are showing up with legends intact.  It seems for some odd reason that the “featureEffect” was causing the problem.

Hopefully this can help others in the future!

Thanks for your help.

Noah-Sager
Esri Regular Contributor

Excellent, thanks for sharing the follow-up solution. My hunch is that the "featureEffect" was sending the layer as a screenshot (known limitation) and layers sent as screenshots do not appear in the printed legend (another known limitation).

Known limits for printing are documented here:

https://developers.arcgis.com/javascript/latest/api-reference/esri-rest-print.html

 

AndrewMurdoch1
Occasional Contributor II

Thanks! 

0 Kudos