Search code examples
javascriptvega-litevegageography

Automatically resize Vega map based on lat/long or geojson


I am attempting to create a map option within a data dashboard, where the map will always be of the state of Texas. For that reason, I don't want to give the user the ability to change the scale or recenter the map, because it's more likely to create confusion than contribute anything beneficial. However nearly all of the Vega documentation examples revolve around maps with that functionality.

I do, however, need the view to change based on the user's screen size and changes to the dashboard window. For that reason I've been trying to use Vega's "fit" and "size" properties, rather than explicitly defining a center and scale. At this point I've gotten the map working, with the legend where it needs to be, colors are all right, etc., but I can't figure out how to get the window to resize on anything other than the full projection. Because I'm working with only a single state, albersUSA is the closest I can get but it's still far too wide of a view.

Example of how the map looks right now

Based on the documentation, I understand "fit" works on geojson data and I've tried using the original map data, and I even went ahead and just created a version with a square the approximate size of Texas, so I could place the coordinates directly into the javascript, but nothing has worked.

Does anyone have any idea on how to get this working?

var figure1 = {
      $schema: "https://vega.github.io/schema/vega/v5.json",
      background: "white",
      autosize: { type: "fit", contains: "padding" },
      signals: [
        {
          name: "width",
          init: "isFinite(containerSize()[0]) ? containerSize()[0] : 200",
          on: [
            {
              update: "isFinite(containerSize()[0]) ? containerSize()[0] : 200",
              events: "window:resize",
            },
          ],
        },
        {
          name: "height",
          init: "isFinite(containerSize()[1]) ? containerSize()[1] : 200",
          on: [
            {
              update: "isFinite(containerSize()[1]) ? containerSize()[1] : 200",
              events: "window:resize",
            },
          ],
        },
      ],
      data: [
        {
          name: "source_1",
          url: "toolData.json",
          format: { type: "json" },
        },
        {
          name: "source_0",
          url: "serviceAreas.geojson",
          format: { property: "features" },
          transform: [
            {
              type: "lookup",
              from: "source_1",
              key: "ID",
              fields: ["properties.ID"],
              values: ["spDevMath"],
            },
          ],
        },
      ],
      projections: [
        {
          name: "projection",
          type: "albersUSA",
          fit: {
            type: "Feature",
            geometry: {
              type: "MultiPolygon",
              coordinates: [
                [
                  [
                    [-107.271508262248858, 37.050404907992352],
                    [-107.193379042010278, 25.721667973398588],
                    [-92.661344077634837, 25.799797193637165],
                    [-92.947817885176278, 36.946232614340914],
                    [-107.271508262248858, 37.050404907992352],
                  ],
                ],
              ],
            },
          },
          size: { signal: "[width, height]" },
        },
      ],
      marks: [
        {
          name: "marks",
          type: "shape",
          style: ["geoshape"],
          from: { data: "source_0" },
          encode: {
            update: {
              fill: { scale: "color", field: "spDevMath" },
              ariaRoleDescription: { value: "geoshape" },
              description: {
                signal: '"spDevMath: " + (format(datum["spDevMath"], ""))',
              },
            },
          },
          transform: [{ type: "geoshape", projection: "projection" }],
        },
      ],
      scales: [
        {
          name: "color",
          type: "linear",
          domain: { data: "source_0", field: "spDevMath" },
          range: "heatmap",
          interpolate: "hcl",
          zero: false,
        },
      ],
      legends: [
        {
          fill: "color",
          gradientLength: { signal: "clamp(height, 64, 200)" },
          title: "rate",
        },
      ],
    };
  }

Solution

  • In your example try this for Vega projections:

       "projections": [
      {
        "name": "projection",
        "type": "albersUsa",
        "fit": {"signal": "data('source_0')"},
        "size": {"signal": "[width - 120,  height]"},
      }  
    ],
    

    Here is a working example of the Vega map of unemployment by county but only for Texas. The topojson file is from https://github.com/deldersveld/topojson. The Texas map resizes and fits within the container when the container size changes.

    View in Vega online editor

    enter image description here