Your First React Section

Display a seismic file selected in the browser, with cancellation, error handling and cleanup.

Compare seismic displays

Compare density and wiggles on the same synthetic section. Drag a box to zoom; double-click to reset.

0.00 ms CPU/frame · 0 frames/s · idle FPS can be zero
<SectionView source={source} path="demo"
  display={{ colormap: 'Seismic', wiggle: false, agc: false }}
  rangeBars style={{ height: 340 }} />

Goal: display a selected SEG-Y or SU file, then release it when the component leaves.

Connect the File to the View

sequenceDiagram
  accTitle: Opening and displaying a local section
  accDescr: The application opens a chosen file, passes the source and returned path to SectionView, then disposes its session when the component leaves.
  participant App
  participant Source as LocalDataSource
  participant View as SectionView
  App->>Source: open(file, signal)
  Source-->>App: FileInfo with session path
  App->>View: source and path
  View->>Source: Metadata and visible tiles
  Source-->>View: Typed data for rendering
  App->>Source: dispose on cleanup

Copy the Component

Install core, React and readers. Pass a File from a file input or drop handler:

'use client'

import { useEffect, useState } from 'react'
import { SectionView } from '@bs/outkrop-react'
import { LocalDataSource } from '@bs/outkrop-readers/browser'

type Session = { source: LocalDataSource; path: string }

export function LocalSection({ file }: { file: File }) {
  const [session, setSession] = useState<Session | null>(null)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    const source = new LocalDataSource()
    const controller = new AbortController()
    setSession(null)
    setError(null)

    void source
      .open(file, { signal: controller.signal })
      .then((info) => {
        if (controller.signal.aborted) return
        if (info.kind !== 'seismic') {
          source.dispose()
          setError('Choose a SEG-Y or SU file.')
          return
        }
        setSession({ source, path: info.path })
      })
      .catch((reason: unknown) => {
        if (!controller.signal.aborted) setError(String(reason))
      })

    return () => {
      controller.abort()
      source.dispose()
    }
  }, [file])

  if (error) return <p role="alert">{error}</p>
  if (!session) return <p role="status">Opening {file.name}…</p>

  return (
    <SectionView
      source={session.source}
      path={session.path}
      style={{ height: 520 }}
      display={{ colormap: 'Seismic', clipMode: 'percentile', clipPercent: 98 }}
      onError={(reason) => setError(String(reason))}
    />
  )
}

Give this component a new key for each selection. Its effect owns the source, aborts unfinished opening and disposes it on cleanup, including StrictMode effect replay.

Adjust the View

Task Prop
Switch to wiggles display={{ wiggle: true }}
Change clipping clipMode: 'auto', 'percentile' or 'manual' inside display
Pan with dragging dragMode="pan"
Show per-axis navigation rangeBars
Save a window onWindowChange

Windows use 1-based trace numbers and milliseconds from the first sample. For depth-domain data, build a core view using its metadata; do not relabel a time axis as depth.

Use view handles for reset, zoom and export. For hosted data, replace the source with HttpDataSource.