Skip to main content

Overview

The Liquid Fill component renders an animated container with a waving liquid surface that rises to represent a percentage value. Supports multiple shapes (circle, rectangle, triangle, etc.) and can display single or multiple values simultaneously.
Dependency: This component requires the echarts-liquidfill plugin to be imported.

Operating Modes

The component operates in two distinct modes:
  1. Single Mode: Displays one value with customizable appearance
  2. Multiple Mode: Displays primary value with optional secondary value

Single Mode Props

value
number
required
The numeric value to display (not percentage). Combined with maxValue to calculate fill percentage.
value={45.5}           // Current measurement
value={null}           // Shows "Sin datos"
maxValue
number
default:"1"
Maximum value for percentage calculation. Percentage = value / maxValue.
maxValue={100}         // value of 75 = 75% fill
maxValue={500}         // value of 250 = 50% fill
color
string
default:"#38bdf8"
Primary liquid color (middle of gradient). Accepts hex colors.
color="#10b981"        // Green
color="#3b82f6"        // Blue
color="#f59e0b"        // Amber
shape
string
default:"circle"
Container shape. Available options:
  • 'circle' - Perfect circle (default)
  • 'rect' - Rectangle
  • 'roundRect' - Rounded rectangle
  • 'triangle' - Triangle
  • 'diamond' - Diamond shape
  • 'pin' - Map pin shape
  • 'arrow' - Arrow shape
shape="circle"         // Round container
shape="roundRect"      // Soft edges
shape="triangle"       // Triangular tank
porcentage
boolean
default:"false"
Display format toggle:
  • true: Shows percentage value (e.g., “75.5 %”)
  • false: Shows absolute value with unit (e.g., “45.50 m³”)
porcentage={true}      // "85.0 %"
porcentage={false}     // "85.00 L"
border
boolean
default:"true"
Enable or disable the decorative outer border with gradient.
border={true}          // Show border (default)
border={false}         // Borderless
unidad
string
default:""
Unit of measurement displayed after the value (only when porcentage={false}).
unidad="m³"            // Cubic meters
unidad="L"             // Liters
unidad="gal"           // Gallons
other
string | false
default:"false"
Optional second line of text below the main value.
other="Tanque Norte"   // Additional label
other={false}          // No additional text

Multiple Mode Props

multipleValues
object
When provided, switches to multiple-value mode. Overrides single-mode props.Object Structure:
multipleValues={{
  value: { value: 45.5 },        // Or just: value: 45.5
  maxValue: 100,                  // Or: maxValue: { value: 100 }
  secondary: {
    varsInflux: { temp: true },  // Presence indicates secondary value exists
    value: 22.5,
    unit: "°C"
  }
}}
value
Primary value. Can be { value: number } or just number.
maxValue
Maximum for percentage calculation. Can be { value: number } or number.
secondary
object
Secondary measurement configuration:
  • varsInflux: Object indicating presence of InfluxDB variables (any keys)
  • value: Numeric value to display
  • unit: Unit string for this value

Shape Configurations

Each shape has optimized parameters for best appearance:
ShapeRadiusAmplitudeWave LengthFont SizeOutline Distance
circle90%890%24px4
rect85%690%24px4
roundRect90%890%24px4
triangle80%890%22px0
diamond90%890%22px4
arrow70%890%18px4
pin100%890%24px4

Visual Effects

Liquid Gradient

The liquid uses a 3-stop vertical linear gradient:
  • Offset 0 (top): #a5f3fc (light cyan)
  • Offset 0.5 (middle): Custom color prop
  • Offset 1 (bottom): #0c4a6e (dark blue)

Wave Animation

Period
4000ms (4 seconds) - Full wave cycle durationSet to 0 when no valid data to freeze animation
Wave Length
90% of container width - Controls wave frequency
Amplitude
6-8px depending on shape - Wave height

Border Gradient

When border={true}, an 8px border is applied with diagonal gradient:
  • Start (top-left): #93c5fd (light blue)
  • End (bottom-right): #1e3a8a (dark blue)

Text Color (Dynamic)

Text color automatically adjusts based on fill level for readability:
  • Fill > 60%: White text (#ffffff)
  • Fill > 40% (multiple mode): White text
  • Fill ≤ 60%: Dark blue text (#0f2a44)

Enter Animation

  • Easing: cubicOut - Smooth deceleration
  • Duration: 1800ms when data is valid, 0ms for no data

Usage Examples

Tank Level Indicator

import LiquidFillPorcentaje from './components/LiquidFillPorcentaje'

function TankLevelGauge({ currentLevel, capacity }) {
  return (
    <div style={{ width: '300px', height: '300px' }}>
      <LiquidFillPorcentaje
        value={currentLevel}
        maxValue={capacity}
        color="#3b82f6"
        shape="circle"
        unidad="m³"
        border={true}
      />
    </div>
  )
}

Percentage Display

import LiquidFillPorcentaje from './components/LiquidFillPorcentaje'

function TreatmentEfficiency({ efficiency }) {
  return (
    <div style={{ width: '250px', height: '250px' }}>
      <LiquidFillPorcentaje
        value={efficiency}
        maxValue={100}
        color="#10b981"
        shape="roundRect"
        porcentage={true}
        border={true}
      />
    </div>
  )
}

Rectangular Tank

import LiquidFillPorcentaje from './components/LiquidFillPorcentaje'

function RectangularTank({ volume, maxVolume }) {
  return (
    <div style={{ width: '200px', height: '350px' }}>
      <LiquidFillPorcentaje
        value={volume}
        maxValue={maxVolume}
        color="#06b6d4"
        shape="rect"
        unidad="L"
        other="Tanque de Reserva"
        border={true}
      />
    </div>
  )
}

Chemical Reservoir

import LiquidFillPorcentaje from './components/LiquidFillPorcentaje'

function ChemicalReservoir({ level }) {
  // Change color based on level
  const getColor = (lvl, max) => {
    const pct = (lvl / max) * 100
    if (pct < 20) return '#ef4444'  // Red - Low
    if (pct < 50) return '#f59e0b'  // Amber - Medium
    return '#10b981'  // Green - Good
  }

  return (
    <div style={{ width: '280px', height: '280px' }}>
      <LiquidFillPorcentaje
        value={level}
        maxValue={500}
        color={getColor(level, 500)}
        shape="triangle"
        unidad="kg"
        other="Sulfato de Aluminio"
      />
    </div>
  )
}

Multiple Values Display

import LiquidFillPorcentaje from './components/LiquidFillPorcentaje'

function MultiSensorTank({ tankData }) {
  const multiData = {
    value: { value: tankData.level },
    maxValue: tankData.capacity,
    secondary: {
      varsInflux: { temperature: true },
      value: tankData.temperature,
      unit: "°C"
    }
  }

  return (
    <div style={{ width: '320px', height: '320px' }}>
      <LiquidFillPorcentaje
        multipleValues={multiData}
        color="#3b82f6"
        shape="roundRect"
        unidad="m³"
        porcentage={false}
        border={true}
      />
    </div>
  )
}

Dashboard Grid

import LiquidFillPorcentaje from './components/LiquidFillPorcentaje'

function TankDashboard({ tanks }) {
  return (
    <div style={{ 
      display: 'grid', 
      gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))',
      gap: '20px'
    }}>
      {tanks.map((tank, idx) => (
        <div key={idx} style={{ height: '280px' }}>
          <h3>{tank.name}</h3>
          <LiquidFillPorcentaje
            value={tank.level}
            maxValue={tank.capacity}
            color={tank.color}
            shape="circle"
            unidad="m³"
            border={true}
          />
        </div>
      ))}
    </div>
  )
}

No Data Handling

import LiquidFillPorcentaje from './components/LiquidFillPorcentaje'

function SafeTankGauge({ level, maxLevel, isOnline }) {
  return (
    <div style={{ width: '300px', height: '300px' }}>
      <LiquidFillPorcentaje
        value={isOnline ? level : null}  // null triggers "Sin datos"
        maxValue={maxLevel}
        color="#10b981"
        shape="circle"
        unidad="m³"
        other={isOnline ? "Sistema Activo" : "Sistema Desconectado"}
      />
    </div>
  )
}

Data Validation

The component validates values using this logic:
const isValidNumber = (v) =>
  v !== null &&
  v !== undefined &&
  v !== '' &&
  !isNaN(Number(v))
Invalid values result in:
  • 0% fill level
  • “Sin datos” text display
  • Gray color scheme
  • No wave animation (frozen)

Shape Selection Guide

Use CaseRecommended ShapeReason
Generic percentagecircleClean, familiar design
Tank levelrect or roundRectMatches physical tank shape
Funnel/HoppertriangleVisual representation
Highlight/BadgediamondDraws attention
Location markerpinGeographic context
Directional flowarrowIndicates direction

Performance Considerations

Animation Performance: Wave animations use Canvas rendering. Limit to fewer than 10 simultaneous liquid fill components for optimal performance.
  • Wave period: 4 seconds (smooth, not CPU-intensive)
  • Frozen state when no data (0ms period)
  • Responsive to container size changes

Accessibility

  • Provide text alternative showing current value and percentage
  • Use semantic HTML labels for tank/container names
  • Ensure sufficient color contrast for text readability
  • Consider adding ARIA attributes for screen reader support

Responsive Design

// Square container (recommended)
<div style={{ width: '100%', maxWidth: '400px', aspectRatio: '1/1' }}>
  <LiquidFillPorcentaje {...props} />
</div>

// Mobile-optimized
<div style={{ 
  width: '100%', 
  maxWidth: window.innerWidth < 768 ? '250px' : '350px',
  aspectRatio: '1/1'
}}>
  <LiquidFillPorcentaje {...props} />
</div>

Color Palette Suggestions

Liquid TypeColorHex Code
Water (clean)Cyan#06b6d4
Water (treated)Blue#3b82f6
Chemical (safe)Green#10b981
Chemical (caution)Amber#f59e0b
Chemical (danger)Red#ef4444
Fuel/OilAmber#f59e0b
GenericSky Blue#38bdf8 (default)

Source Reference

File: ~/workspace/source/src/modules/Charts/components/LiquidFillPorcentaje.jsx:65 Dependency: echarts-liquidfill plugin required Built with Apache ECharts and echarts-liquidfill for the Centinela water treatment monitoring system.