Unique value renderer

Download Sample Viewer

Description

This sample demonstrates that the client can override the unique value renderers specified by a dynamic map service layer. The dynamic layer needs to be enabled for dynamic rendering by calling setEnableDynamicLayers(true) on the layer before it is added to the map. The new renderers are created client-side but the information is applied at the server level when rendering the map image.

Code snippet


    // Create new drawing info from our renderer, with set transparency
    DrawingInfo drawingInfo = new DrawingInfo(renderer, TRANSPARENCY);
    
    // Get the layerInfo from the dynamic layer and set the drawing info
    DynamicLayerInfoCollection layerInfos = dynamicLayer.getDynamicLayerInfos();
    DynamicLayerInfo layerInfo = layerInfos.get(layerId);
    layerInfo.setDrawingInfo(drawingInfo);

    // Refresh the layer
    dynamicLayer.refresh();
  

Sample Code

/* Copyright 2014 Esri

All rights reserved under the copyright laws of the United States
and applicable international laws, treaties, and conventions.

You may freely redistribute and use this sample code, with or
without modification, provided you include the original copyright
notice and use restrictions.

See the use restrictions.*/
package com.esri.client.samples.dynamiclayers;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Random;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;

import com.esri.client.local.ArcGISLocalDynamicMapServiceLayer;
import com.esri.client.local.ArcGISLocalTiledLayer;
import com.esri.core.geometry.Envelope;
import com.esri.core.map.DrawingInfo;
import com.esri.core.map.DynamicLayerInfo;
import com.esri.core.map.DynamicLayerInfoCollection;
import com.esri.core.renderer.AlgorithmicColorRamp;
import com.esri.core.renderer.ColorRamp;
import com.esri.core.renderer.MultipartColorRamp;
import com.esri.core.renderer.RampDefinition;
import com.esri.core.renderer.Renderer;
import com.esri.core.renderer.UniqueValueDefinition;
import com.esri.core.renderer.UniqueValueRenderer;
import com.esri.core.symbol.SimpleFillSymbol;
import com.esri.core.symbol.SimpleLineSymbol;
import com.esri.core.symbol.SimpleMarkerSymbol;
import com.esri.core.symbol.SimpleMarkerSymbol.Style;
import com.esri.core.tasks.ags.GenerateRendererTask;
import com.esri.core.tasks.ags.GenerateRendererTaskParameters;
import com.esri.map.JMap;
import com.esri.map.LayerInitializeCompleteEvent;
import com.esri.map.LayerInitializeCompleteListener;
import com.esri.map.LayerList;
import com.esri.runtime.ArcGISRuntime;

/***
 * This sample demonstrates that the client can override the unique value renderers
 * specified by a dynamic map service layer.  The dynamic layer needs to be enabled
 * for dynamic rendering by calling  <code>setEnableDynamicLayers(true)</code> on
 * the layer before it is added to the map. The new renderers are created client-side
 * but the information is applied at the server level when rendering the map image.
 * <p>
 * This sample uses the execute method from the <code>GenerateRendererTask</code>
 * class to generate a new unique value renderer with the chosen parameters.
 *
 */
public class LocalDynamicUniqueRenderer {

  private JComponent contentPane;
  private JMap map;
  private ArcGISLocalDynamicMapServiceLayer dynamicLayer;
  private JProgressBar progressBar;
  Random random;
  JButton citiesButton;
  JButton citiesDefaultButton;
  JButton highwaysButton;
  JButton highwaysDefaultButton;
  JButton statesButton;
  JButton statesDefaultButton;
  Color fromColor;
  Color midColor;
  Color toColor;

  private static final int TRANSPARENCY = 20; // 0 is opaque, 100 is transparent
  private static final int BUTTON_WIDTH = 220;

  // Constructor
  public LocalDynamicUniqueRenderer() { }

  // ------------------------------------------------------------------------
  // Core functionality
  // ------------------------------------------------------------------------
  /**
   * Sets the drawing info of sublayer number 'layerId' of a dynamic layer
   * with the given renderer
   * @param renderer
   * @param layerId
   */
  private void render(Renderer renderer, int layerId) {
    // Create new drawing info from our renderer, with set transparency
    DrawingInfo drawingInfo = new DrawingInfo(renderer, TRANSPARENCY);

    // Get the layerInfo from the dynamic layer and set the drawing info
    DynamicLayerInfoCollection layerInfos = dynamicLayer.getDynamicLayerInfos();
    DynamicLayerInfo layerInfo = layerInfos.get(layerId);
    layerInfo.setDrawingInfo(drawingInfo);

    // Refresh the layer
    dynamicLayer.refresh();
  }

  /**
   * Resets the default rendering options of sublayer number 'layerId' of
   * the dynamic layer
   */
  private void resetDefault(int layerId) {
    DynamicLayerInfo layerInfo = dynamicLayer.getDynamicLayerInfos().get(layerId);
    layerInfo.resetToDefault();
    dynamicLayer.refresh();
  }

  /**
   * This method uses the <code>GenerateRendererTask</code> class to generate a
   * unique value renderer client-side using the parameters passed in. The color ramp
   * is generated using a random 'to' and 'from' color, and a set <code>RampDefinition</code>
   * algorithm.
   * @param layerId the layer to get the renderer for
   * @param selectedField the field used to generate the renderer
   * @return uvRenderer the unique value renderer generated
   */
  private UniqueValueRenderer getUniqueValueRenderer(int layerId, String selectedField) {
    ArrayList<String> uniqueValueFields = new ArrayList<>();
    uniqueValueFields.add(selectedField);
    UniqueValueDefinition classificationDef = new UniqueValueDefinition(uniqueValueFields);

    // create a ColorRamp
    // multipart color ramp looks better for many unique values
    ColorRamp colorRamp1 =
        new AlgorithmicColorRamp(fromColor.getRGB(), midColor.getRGB(), RampDefinition.Algorithm.HSV);
    ColorRamp colorRamp2 =
        new AlgorithmicColorRamp(midColor.getRGB(), toColor.getRGB(), RampDefinition.Algorithm.HSV);
    MultipartColorRamp colorRamp = new MultipartColorRamp();
    colorRamp.add(colorRamp1);
    colorRamp.add(colorRamp2);
    classificationDef.setColorRamp(colorRamp);

    // set a base symbol in order to see the colors better
    switch (layerId) {
      case 0: // Cities
        classificationDef.setBaseSymbol(
            new SimpleMarkerSymbol(Color.WHITE, 6, Style.CIRCLE)); // larger circle
        break;
      case 1: // Highways
        classificationDef.setBaseSymbol(
            new SimpleLineSymbol(Color.WHITE, 2)); // thicker line
        break;
      case 2: // States
        classificationDef.setBaseSymbol(new SimpleFillSymbol(
            Color.WHITE, new SimpleLineSymbol(Color.BLACK, 1)));
        break;
    }

    // generate the renderer
    GenerateRendererTask rendererTask = new GenerateRendererTask(
        dynamicLayer.getUrl() + "/" + layerId);
    GenerateRendererTaskParameters taskParams = new GenerateRendererTaskParameters(classificationDef);
    UniqueValueRenderer uvRenderer = null;
    try {
      uvRenderer = (UniqueValueRenderer) rendererTask.execute(taskParams);
    } catch (Exception e) {
      e.printStackTrace();
    }
    return uvRenderer;
  }

  // ------------------------------------------------------------------------
  // Static methods
  // ------------------------------------------------------------------------
  /**
   * Starting point of this application.
   * @param args arguments to this application.
   */
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        try {
          // instance of this application
          LocalDynamicUniqueRenderer app = new LocalDynamicUniqueRenderer();

          // create the UI, including the map, for the application.
          JFrame appWindow = app.createWindow();
          appWindow.add(app.createUI());
          appWindow.setVisible(true);
        } catch (Exception e) {
          // on any error, display the stack trace.
          e.printStackTrace();
        }
      }
    });
  }

  // ------------------------------------------------------------------------
  // Public methods
  // ------------------------------------------------------------------------
  /**
   * Creates and displays the UI, including the map, for this application.
   * @return the UI component.
   */
  public JComponent createUI() {

    random = new Random();

    contentPane = createContentPane();

    // button panel
    JPanel buttonPanel = createUserPanel();
    contentPane.add(buttonPanel);

    // progress bar
    progressBar = createProgressBar(contentPane);
    contentPane.add(progressBar);

    // create map
    map = createMap();
    contentPane.add(map);

    return contentPane;
  }


  // ------------------------------------------------------------------------
  // Private methods
  // ------------------------------------------------------------------------
  /**
   * Creates the map.
   * @return a map.
   */
  private JMap createMap() {

    final JMap jMap = new JMap();
    jMap.setExtent(new Envelope(-15000000, 2000000, -7000000, 8000000));

    // setting a tiled layer as basemap
    ArcGISLocalTiledLayer tiledLayer = new ArcGISLocalTiledLayer(getPathSampleData() + "tpks/Topographic.tpk");
    final LayerList layers = jMap.getLayers();
    layers.add(tiledLayer);

    updateProgresBarUI("Starting local dynamic map service...", true);
    // create the dynamic layer
    dynamicLayer = new ArcGISLocalDynamicMapServiceLayer(getPathSampleData() + "mpks/USCitiesStates.mpk");
    // Allow the client to override the default rendering options by setting the enabling
    // dynamic layers to be true. This must be done before adding the layer to the map.
    dynamicLayer.setEnableDynamicLayers(true);
    dynamicLayer
        .addLayerInitializeCompleteListener(new LayerInitializeCompleteListener() {
          @Override
          public void layerInitializeComplete(LayerInitializeCompleteEvent arg0) {
            synchronized (progressBar) {
              if (arg0.getID() == LayerInitializeCompleteEvent.LOCALLAYERCREATE_ERROR) {
                String errMsg = "Failed to initialize due to "
                    + dynamicLayer.getInitializationError();
                JOptionPane.showMessageDialog(jMap, wrap(errMsg), "", JOptionPane.ERROR_MESSAGE);
              }
              updateProgresBarUI(null, false);
            }
            // activate buttons once the dynamic layer is done initializing
            citiesButton.setEnabled(true);
            citiesDefaultButton.setEnabled(true);
            highwaysButton.setEnabled(true);
            highwaysDefaultButton.setEnabled(true);
            statesButton.setEnabled(true);
            statesDefaultButton.setEnabled(true);

          }

        });
    // then, add the layer to the map
    layers.add(dynamicLayer);

    return jMap;
  }

  private JPanel createUserPanel() {
    JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
    panel.setSize(BUTTON_WIDTH + 10, 280);
    panel.setLocation(10, 10);

    // create the buttons
    citiesButton = createCitiesButton();
    citiesDefaultButton = createCitiesDefaultButton();
    highwaysButton = createHighwaysButton();
    highwaysDefaultButton = createHighwaysDefaultButton();
    statesButton = createStatesButton();
    statesDefaultButton = createStatesDefaultButton();

    // renderer settings UI elements
    JLabel lblRenderer = new JLabel("Choose Renderer colors:");
    lblRenderer.setForeground(Color.WHITE);

    JPanel colorPanel = createColorPanel();

    // layout all the components together into a panel
    panel.setBackground(new Color(0, 0, 0, 120));
    panel.add(lblRenderer);
    panel.add(Box.createRigidArea(new Dimension(0,5)));
    panel.add(colorPanel);
    panel.add(Box.createRigidArea(new Dimension(0,20)));
    panel.add(citiesButton);
    panel.add(Box.createRigidArea(new Dimension(0,5)));
    panel.add(citiesDefaultButton);
    panel.add(Box.createRigidArea(new Dimension(0,15)));
    panel.add(highwaysButton);
    panel.add(Box.createRigidArea(new Dimension(0,5)));
    panel.add(highwaysDefaultButton);
    panel.add(Box.createRigidArea(new Dimension(0,15)));
    panel.add(statesButton);
    panel.add(Box.createRigidArea(new Dimension(0,5)));
    panel.add(statesDefaultButton);
    panel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    return panel;
  }

  private JButton createCitiesButton() {
    JButton button = new JButton("Change Cities Renderer");
    button.setMaximumSize(new Dimension(BUTTON_WIDTH, 25));
    button.setMinimumSize(new Dimension(BUTTON_WIDTH, 25));
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        String selectedField = "CLASS"; // could have user select a field instead
        UniqueValueRenderer uvRenderer = getUniqueValueRenderer(0, selectedField);
        render(uvRenderer, 0);
      }
    });
    button.setEnabled(false);
    return button;
  }

  private JButton createCitiesDefaultButton() {
    JButton button = new JButton("Reset Cities Renderer");
    button.setMaximumSize(new Dimension(BUTTON_WIDTH, 25));
    button.setMinimumSize(new Dimension(BUTTON_WIDTH, 25));
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        resetDefault(0);
      }
    });
    button.setEnabled(false);
    return button;
  }

  private JButton createHighwaysButton() {
    JButton button = new JButton("Change Highways Renderer");
    button.setMaximumSize(new Dimension(BUTTON_WIDTH, 25));
    button.setMinimumSize(new Dimension(BUTTON_WIDTH, 25));
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        String selectedField = "TYPE"; // could have user select a field instead
        UniqueValueRenderer uvRenderer = getUniqueValueRenderer(1, selectedField);
        render(uvRenderer, 1);
      }
    });
    button.setEnabled(false);
    return button;
  }

  private JButton createHighwaysDefaultButton() {
    JButton button = new JButton("Reset Highways Renderer");
    button.setMaximumSize(new Dimension(BUTTON_WIDTH, 25));
    button.setMinimumSize(new Dimension(BUTTON_WIDTH, 25));
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        resetDefault(1);
      }
    });
    button.setEnabled(false);
    return button;
  }

  private JButton createStatesButton() {
    JButton button = new JButton("Change States Renderer");
    button.setMaximumSize(new Dimension(BUTTON_WIDTH, 25));
    button.setMinimumSize(new Dimension(BUTTON_WIDTH, 25));
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        String selectedField = "SUB_REGION"; // could have user select a field instead
        UniqueValueRenderer uvRenderer = getUniqueValueRenderer(2, selectedField);
        render(uvRenderer, 2);
      }
    });
    button.setEnabled(false);
    return button;
  }

  private JButton createStatesDefaultButton() {
    JButton button = new JButton("Reset States Renderer");
    button.setMaximumSize(new Dimension(BUTTON_WIDTH, 25));
    button.setMinimumSize(new Dimension(BUTTON_WIDTH, 25));
    button.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        resetDefault(2);
      }
    });
    button.setEnabled(false);
    return button;
  }

  private JPanel createColorPanel() {

    // set some default colors
    fromColor = new Color(0, 153, 0);
    midColor = Color.YELLOW;
    toColor = new Color(204, 0, 0);

    final JButton fromButton = new JButton();
    fromButton.setBackground(fromColor);
    fromButton.setMaximumSize(new Dimension(20, 20));
    fromButton.setMinimumSize(new Dimension(20, 20));
    fromButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        fromColor = JColorChooser.showDialog(
            contentPane,
            "Choose 'from' color",
            fromButton.getBackground());
        fromButton.setBackground(fromColor);
      }
    });

    final JButton midButton = new JButton();
    midButton.setBackground(midColor);
    midButton.setMaximumSize(new Dimension(20, 20));
    midButton.setMinimumSize(new Dimension(20, 20));
    midButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        midColor = JColorChooser.showDialog(
            contentPane,
            "Choose 'mid' color",
            midButton.getBackground());
        midButton.setBackground(midColor);
      }
    });

    final JButton toButton = new JButton();
    toButton.setBackground(toColor);
    toButton.setMaximumSize(new Dimension(20, 20));
    toButton.setMinimumSize(new Dimension(20, 20));
    toButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent arg0) {
        toColor = JColorChooser.showDialog(
            contentPane,
            "Choose 'to' color",
            toButton.getBackground());
        toButton.setBackground(toColor);
      }
    });

    JLabel lblFrom = new JLabel("'from':  ");
    lblFrom.setForeground(Color.WHITE);
    JLabel lblMid = new JLabel("'mid':  ");
    lblMid.setForeground(Color.WHITE);
    JLabel lblTo = new JLabel("'to':  ");
    lblTo.setForeground(Color.WHITE);

    JPanel colorPanel = new JPanel();
    colorPanel.setLayout(new BoxLayout(colorPanel, BoxLayout.X_AXIS));
    colorPanel.setMaximumSize(new Dimension(BUTTON_WIDTH, 20));
    colorPanel.setMinimumSize(new Dimension(BUTTON_WIDTH, 20));
    colorPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
    colorPanel.setBackground(new Color(0, 0, 0, 0));
    colorPanel.add(lblFrom);
    colorPanel.add(fromButton);
    colorPanel.add(Box.createRigidArea(new Dimension(10, 0)));
    colorPanel.add(lblMid);
    colorPanel.add(midButton);
    colorPanel.add(Box.createRigidArea(new Dimension(10, 0)));
    colorPanel.add(lblTo);
    colorPanel.add(toButton);

    return colorPanel;
  }

  /**
   * Creates a content pane.
   * @return a content pane.
   */
  private static JLayeredPane createContentPane() {
    JLayeredPane contentPane = new JLayeredPane();
    contentPane.setBounds(100, 100, 1000, 700);
    contentPane.setLayout(new BorderLayout(0, 0));
    contentPane.setVisible(true);
    return contentPane;
  }

  /**
   * Creates a progress bar.
   * @param parent progress bar's parent. The horizontal axis of the progress bar will be
   * center-aligned to the parent.
   * @return a progress bar.
   */
  private static JProgressBar createProgressBar(final JComponent parent) {
    final JProgressBar progressBar = new JProgressBar();
    progressBar.setSize(280, 20);
    parent.addComponentListener(new ComponentAdapter() {
      @Override
      public void componentResized(ComponentEvent e) {
        progressBar.setLocation(
            parent.getWidth()/2 - progressBar.getWidth()/2,
            parent.getHeight() - progressBar.getHeight() - 20);
      }
    });
    progressBar.setStringPainted(true);
    progressBar.setIndeterminate(true);
    return progressBar;
  }

  /**
   * Updates progress bar UI from the Swing's Event Dispatch Thread.
   * @param str string to be set.
   * @param visible flag to indicate visibility of the progress bar.
   */
  private void updateProgresBarUI(final String str, final boolean visible) {
    SwingUtilities.invokeLater(new Runnable() {
      @Override
      public void run() {
        if (str != null) {
          progressBar.setString(str);
        }
        progressBar.setVisible(visible);
      }
    }); 
  }

  /**
   * Creates a window.
   * @return a window.
   */
  private JFrame createWindow() {
    JFrame window = new JFrame("Local Dynamic Layers: Unique Value Renderer Sample");
    window.setBounds(100, 100, 1000, 700);
    window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    window.getContentPane().setLayout(new BorderLayout(0, 0));
    window.addWindowListener(new WindowAdapter() {
      @Override
      public void windowClosing(WindowEvent windowEvent) {
        super.windowClosing(windowEvent);
        map.dispose();
      }
    });
    return window;
  }

  private String getPathSampleData() {
    String FSP = System.getProperty("file.separator");
    String dataPath = null;
    String javaPath = ArcGISRuntime.getInstallDirectory();
    if (javaPath != null) {
      if (!(javaPath.endsWith("/") || javaPath.endsWith("\\"))){
        javaPath += FSP;
      }
      dataPath = javaPath + "sdk" + FSP + "samples" + FSP + "data" + FSP;
    }
    File dataFile = new File(dataPath);
    if (!dataFile.exists()) { 
      dataPath = ".." + FSP + "data" + FSP;
    }
    return dataPath;
  }
  
  private String wrap(String str) {
    // create a HTML string that wraps text when longer
    return "<html><p style='width:200px;'>" + str + "</html>";
  }
}
Feedback on this topic?