Skip to content

Latest commit

 

History

History
566 lines (428 loc) · 16.2 KB

File metadata and controls

566 lines (428 loc) · 16.2 KB

ArcGIS 3D Highway Segments Implementation Plan

Project Overview

Convert an existing 2D ArcGIS map in a Next.js web application to 3D SceneView, displaying stacked highway segments organized by year. Each year's segments will be positioned at a different elevation to create a vertical "history stack" that visualizes highway changes over time.


Objectives

  • Replace 2D MapView with 3D SceneView in Next.js application
  • Display highway segments from TxDOT/similar data source
  • Stack segments by year using elevation (z-values)
  • Enable 3D interaction (rotation, tilt, zoom)
  • Maintain existing data structure and feature service integration

Architecture

Current State

  • Next.js application running on web
  • 2D ArcGIS map (MapView) displaying highway segments
  • Feature service or layer containing highway geometry

Target State

  • Next.js application with 3D ArcGIS map (SceneView)
  • Highway segments stacked vertically by year
  • 3D basemap with elevation surface
  • Interactive 3D navigation and visualization

Key Components

Next.js App
    ├── SceneView Component (replaces MapView)
    ├── Map Object (with 3D basemap + elevation ground)
    ├── FeatureLayer (highways with elevation info)
    ├── Renderer (3D symbol styling)
    └── UI Controls (optional: year filter, legend, camera)

Technical Stack

  • Framework: Next.js (React)
  • GIS Library: ArcGIS Maps SDK for JavaScript 4.x
  • View Type: SceneView (3D)
  • Data Source: Feature Service (HTTP REST endpoint)
  • Styling: 3D Symbols (LineSymbol3D, PolygonSymbol3D)

Implementation Phases

Phase 1: Setup & Dependencies

Goal: Prepare Next.js project for ArcGIS 3D development

Tasks:

  1. Verify ArcGIS SDK Installation

    • Confirm @arcgis/core package is installed
    • Update to latest version if needed: npm install @arcgis/core@latest
    • Verify version is 4.25+
  2. Create/Update Map Component

    • Create new component: components/HighwayScene3D.jsx
    • Use 'use client' directive for Next.js 13+ App Router
    • Set up useEffect hook for view initialization
  3. Configure Module Imports

    • Import SceneView (not MapView)
    • Import FeatureLayer
    • Import 3D symbol classes (LineSymbol3D, PolygonSymbol3D, etc.)
    • Test that imports resolve without errors

Deliverable: Component template with proper imports, no errors


Phase 2: Convert MapView to SceneView

Goal: Replace 2D map with 3D scene

Tasks:

  1. Update Map Configuration

    • Change basemap from 2D (e.g., 'streets') to 3D (e.g., 'topo-3d')
    • Add ground: 'world-elevation' to map constructor
    • Verify basemap displays with terrain/elevation
  2. Replace View Constructor

    • Remove MapView import/instantiation
    • Create SceneView instead:
      const view = new SceneView({
        map,
        container: mapDiv.current,
        center: [-99.9, 33.5],  // TxDOT focus area
        zoom: 10,
        tilt: 45,
        heading: 0
      });
  3. Set Initial Camera Position

    • Center on highway area (Texas coordinates: ~-99.9°, 33.5°)
    • Set zoom level appropriate for highway visibility (zoom 10-12)
    • Set tilt to show 3D perspective (45° recommended)
    • Optional: set heading for directional view
  4. Verify 3D Rendering

    • Check that terrain/elevation displays
    • Confirm camera tilt/rotation works
    • Test zoom and pan interactions

Deliverable: Functional 3D map with terrain, correct center/zoom


Phase 3: Data Preparation & Analysis

Goal: Ensure highway data has year information for stacking

Tasks:

  1. Audit Current Feature Service

    • Document feature service URL
    • List all available attributes/fields
    • Identify year-related field (e.g., YEAR_COMPLETED, SURVEY_YEAR, CONSTRUCTION_YEAR)
    • Check data type (numeric vs. string) and value range
  2. Verify Geometry Type

    • Confirm segments are line geometry (not point or polygon)
    • Check for any invalid geometries
    • Test query to feature service returns expected data
  3. Add Year Attribute if Missing

    • If no year field exists, create one in ArcGIS Pro or data source
    • Populate with historical construction/modification dates
    • Options:
      • Import from external database
      • Manually attribute in GIS
      • Use field calculation if pattern exists
    • Republish feature service after changes
  4. Document Data Mapping

    • Create reference table: Year → Z-height formula
    • Example: Year 1980 = 0m, Year 1981 = 100m, Year 1982 = 200m
    • Confirm no duplicate years for same segment (or decide how to handle)

Deliverable: Data audit document + validated feature service with year field


Phase 4: Implement Elevation Info (Z-Value Stacking)

Goal: Position segments at different elevations by year

Tasks:

  1. Add FeatureLayer with Elevation Info

    const highwayLayer = new FeatureLayer({
      url: 'https://your-service-url/FeatureServer/0',
      elevationInfo: {
        mode: 'absolute-height',  // or 'relative-to-ground'
        featureExpressionInfo: {
          expression: `(($feature.YEAR - 1980) * 100)`
        }
      }
    });
  2. Define Elevation Formula

    • Base year: 1980 (first year of data, or adjust as needed)
    • Height increment per year: 100m (adjustable)
    • Formula: (Year - BaseYear) * Increment
    • Test with sample years to verify correct spacing
  3. Choose Elevation Mode

    • absolute-height: Use z-values directly (ground = 0m, stack above)
    • relative-to-ground: Add z-value to terrain elevation
    • Recommendation: Use absolute-height for consistent stacking
  4. Test Layer Addition

    • Add layer to map: map.add(highwayLayer)
    • Verify segments appear in 3D at expected heights
    • Check for rendering errors in console

Deliverable: Highway layer displays stacked by year with correct z-positions


Phase 5: Apply 3D Rendering & Styling

Goal: Make stacked segments visually distinct and recognizable

Tasks:

  1. Define 3D Symbol (LineSymbol3D)

    const renderer = new SimpleRenderer({
      symbol: new LineSymbol3D({
        symbolLayers: [
          new LineSymbolLayer({
            material: { color: [0, 120, 215] },
            size: 6  // width in pixels
          })
        ]
      })
    });
  2. Apply Renderer to Layer

    • Set renderer on FeatureLayer
    • Verify lines appear with correct color/width in 3D
  3. Optional: Color-Code by Year

    • Create ClassBreaksRenderer or UniqueValueRenderer
    • Assign different colors to year ranges
    • Example: 1980-1990 = Blue, 1990-2000 = Green, etc.
    • Helps distinguish stacked layers visually
  4. Optional: Add Extrusion

    • Create vertical walls/ribbons instead of lines
    • Use PolygonSymbol3D for buffer geometry
    • Experiment with transparency/opacity
  5. Test Visual Appearance

    • Zoom in/out to verify symbol scaling
    • Rotate camera to see layers from different angles
    • Adjust color/size for clarity

Deliverable: Visually distinct 3D segments, color-coded or styled appropriately


Phase 6: Integration & Testing

Goal: Integrate 3D component into Next.js application

Tasks:

  1. Import Component in Page/Layout

    • Add HighwayScene3D component to main page
    • Set container to full viewport (width: 100%, height: 100vh)
    • Verify no layout issues
  2. Test Performance

    • Load map with all years of data
    • Measure frame rate (aim for 60 FPS)
    • If slow, implement layer filtering or data reduction
    • Monitor memory usage in DevTools
  3. Browser Compatibility

    • Test on Chrome, Firefox, Safari, Edge
    • Check mobile responsiveness (if applicable)
    • Verify touch controls work for 3D navigation
  4. Error Handling

    • Add try/catch around view initialization
    • Log errors to console for debugging
    • Handle case where feature service is unavailable

Deliverable: Fully integrated, tested, performant 3D map


Phase 7: Enhanced Features (Optional)

Goal: Add interactive controls and visualizations

Tasks:

  1. Year Filter/Slider

    • Create UI slider to select year range
    • Filter FeatureLayer using definitionExpression
    • Example: definitionExpression = "YEAR >= 2000 AND YEAR <= 2020"
    • Update view dynamically as user adjusts slider
  2. Legend

    • Display year ranges and corresponding colors
    • Show what each stacked layer represents
    • Update legend based on active filters
  3. Camera Controls

    • Add buttons to rotate/tilt camera
    • Preset views (top-down, angled, side view)
    • Auto-fly to feature on selection
  4. Layer Toggling

    • Add checkboxes to show/hide specific years
    • Useful for comparing two years side-by-side
  5. Popup/Info Panel

    • Click segment to show highway details
    • Display year, road name, length, etc.
    • Add hyperlinks or more actions

Deliverable: Enhanced UI with controls, legend, and interactivity


Code Snippets & Templates

Basic Next.js Component

'use client';

import { useEffect, useRef } from 'react';
import { Map } from '@arcgis/core/Map';
import { SceneView } from '@arcgis/core/views/SceneView';
import { FeatureLayer } from '@arcgis/core/layers/FeatureLayer';
import { SimpleRenderer } from '@arcgis/core/renderers/SimpleRenderer';
import { LineSymbol3D } from '@arcgis/core/symbols/LineSymbol3D';
import { LineSymbolLayer } from '@arcgis/core/symbols/LineSymbolLayer';

export default function HighwayScene3D() {
  const mapDiv = useRef(null);

  useEffect(() => {
    const map = new Map({
      basemap: 'topo-3d',
      ground: 'world-elevation'
    });

    const view = new SceneView({
      map,
      container: mapDiv.current,
      center: [-99.9, 33.5],
      zoom: 10,
      tilt: 45
    });

    const highways = new FeatureLayer({
      url: 'https://your-service-url/FeatureServer/0',
      renderer: new SimpleRenderer({
        symbol: new LineSymbol3D({
          symbolLayers: [
            new LineSymbolLayer({
              material: { color: [0, 120, 215] },
              size: 6
            })
          ]
        })
      }),
      elevationInfo: {
        mode: 'absolute-height',
        featureExpressionInfo: {
          expression: '(($feature.YEAR - 1980) * 100)'
        }
      }
    });

    map.add(highways);

    return () => view.destroy();
  }, []);

  return <div ref={mapDiv} style={{ width: '100%', height: '100vh' }} />;
}

Elevation Formula Variations

// Option 1: Simple year-based (each year = 100m)
expression: '(($feature.YEAR - 1980) * 100)'

// Option 2: Custom scaling (smaller increments)
expression: '(($feature.YEAR - 1980) * 50)'

// Option 3: Logarithmic scaling (less cramped for large year ranges)
expression: 'Log(($feature.YEAR - 1980 + 1)) * 200'

// Option 4: Conditional (different heights for different road types)
expression: `
  var roadType = $feature.ROAD_TYPE;
  var yearHeight = ($feature.YEAR - 1980) * 100;
  return roadType == 'Interstate' ? yearHeight + 100 : yearHeight;
`

Data Flow Diagram

Feature Service (REST API)
    ↓
    ├─ Geometry (Line)
    ├─ YEAR Attribute
    └─ Other attributes (name, length, etc.)
    ↓
FeatureLayer
    ↓
Elevation Calculation
    ├─ Formula: (YEAR - 1980) * 100
    └─ Result: Z-height per segment
    ↓
3D Renderer
    ├─ Symbol: LineSymbol3D
    ├─ Color: Based on year or fixed
    └─ Size: 6px width
    ↓
SceneView
    ├─ Basemap: topo-3d
    ├─ Ground: world-elevation
    └─ Segments stacked vertically by year
    ↓
User Interaction
    ├─ Rotate/Tilt camera
    ├─ Filter by year (optional)
    ├─ Click for details (optional)
    └─ Explore 3D history

Dependencies & Versions

Package Version Purpose
@arcgis/core 4.25+ ArcGIS Maps SDK for JavaScript
react 18+ UI framework (Next.js requirement)
next 13+ App Router support
node 18+ Runtime

File Structure

project-root/
├── app/
│   ├── page.jsx
│   └── layout.jsx
├── components/
│   ├── HighwayScene3D.jsx          ← Main 3D map component
│   ├── YearSlider.jsx              ← (Optional) Year filter
│   ├── Legend.jsx                  ← (Optional) Legend
│   └── ControlPanel.jsx            ← (Optional) UI controls
├── utils/
│   └── arcgis-config.js            ← Service URLs, constants
├── public/
└── package.json

Configuration Constants

Create utils/arcgis-config.js:

export const ARCGIS_CONFIG = {
  // Feature Service
  HIGHWAY_SERVICE_URL: 'https://services.arcgis.com/...',
  
  // Map settings
  BASEMAP: 'topo-3d',
  CENTER: [-99.9, 33.5],  // TxDOT area
  ZOOM: 10,
  TILT: 45,
  
  // Elevation stacking
  BASE_YEAR: 1980,
  HEIGHT_INCREMENT: 100,  // meters per year
  
  // Styling
  LINE_COLOR: [0, 120, 215],
  LINE_WIDTH: 6
};

Testing Checklist

  • 3D map renders without errors
  • Terrain/elevation displays correctly
  • Highway segments appear stacked by year
  • Camera tilt/rotation works smoothly
  • Zoom in/out functions correctly
  • Layer responds to filtering (if implemented)
  • No console errors or warnings
  • Performance acceptable (60+ FPS)
  • Mobile-responsive (if applicable)
  • Works in target browsers (Chrome, Firefox, Safari, Edge)

Troubleshooting Guide

Issue: Segments don't appear in 3D view

  • Solution: Verify elevationInfo mode is correct, check feature service URL, inspect network tab for failed requests

Issue: All segments at same height (no stacking)

  • Solution: Check YEAR attribute has numeric values, verify elevation formula in expression, ensure baseYear matches data

Issue: Map loads slowly

  • Solution: Filter to fewer years initially, reduce symbol complexity, implement clustering for dense areas

Issue: 3D symbols not rendering

  • Solution: Verify LineSymbol3D import, check that symbolLayers array has at least one layer, test with basic color value

Issue: SceneView container appears blank

  • Solution: Confirm ref is attached to div, check view constructor has correct container, verify map has basemap assigned

Deployment Considerations

  • Ensure feature service is accessible from production environment (check CORS headers)
  • Test 3D performance on target hardware
  • Optimize bundle size (ArcGIS SDK can be large—consider lazy loading)
  • Monitor CDN usage if using esri-hosted resources
  • Keep ArcGIS Maps SDK version consistent across environments

Next Steps

  1. Immediate (Week 1):

    • Set up component template (Phase 1)
    • Replace MapView with SceneView (Phase 2)
    • Verify 3D basemap renders
  2. Short-term (Week 1-2):

    • Audit and prepare data (Phase 3)
    • Implement elevation stacking (Phase 4)
    • Apply 3D styling (Phase 5)
  3. Medium-term (Week 2-3):

    • Integration and testing (Phase 6)
    • Bug fixes and optimization
    • Deployment to staging
  4. Long-term (Week 3+):

    • Enhanced features (Phase 7): year filter, legend, popups
    • User feedback and refinement
    • Production deployment

References


Questions & Contact

  • Component Setup Issues: Check ArcGIS SDK imports and Next.js useEffect patterns
  • Data Questions: Verify feature service structure and year attribute mapping
  • Performance Issues: Use Chrome DevTools Performance tab to profile rendering
  • Deployment Issues: Test CORS headers on feature service, check production URLs