PHPackages                             gsferro/filament-odometer-easy - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Admin Panels](/categories/admin)
4. /
5. gsferro/filament-odometer-easy

ActiveLibrary[Admin Panels](/categories/admin)

gsferro/filament-odometer-easy
==============================

Animated counters for Filament v3, v4 and v5 — tables, infolists, stats and navigation badges — powered by number-flow (default) or odometer.js.

v1.1.0(today)04↑2900%MITPHPPHP ^8.2CI passing

Since Jul 28Pushed todayCompare

[ Source](https://github.com/gsferro/filament-odometer-easy)[ Packagist](https://packagist.org/packages/gsferro/filament-odometer-easy)[ Docs](https://github.com/gsferro/filament-odometer-easy)[ GitHub Sponsors](https://github.com/gsferro)[ RSS](/packages/gsferro-filament-odometer-easy/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (11)Versions (3)Used By (0)

 [![filament-odometer-easy](/art/logo.png)](/art/logo.png)

 [ ![Latest Version](https://camo.githubusercontent.com/ff95984135d3ad184db3c1fefc691ee633ba607cd81e13688647323bf2dc3c89/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6773666572726f2f66696c616d656e742d6f646f6d657465722d65617379) ](https://packagist.org/packages/gsferro/filament-odometer-easy) [ ![Total Downloads](https://camo.githubusercontent.com/fa9301ddcbcb4b97b2f1dbfb6c13cbdc8445cdf362db5cd03bb5d240a21ee476/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6773666572726f2f66696c616d656e742d6f646f6d657465722d65617379) ](https://packagist.org/packages/gsferro/filament-odometer-easy) [ ![License](https://camo.githubusercontent.com/a2bd88b0cc2924e004d516288bfe16859a6a0edaf3f2145a8da8498cd46da280/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6773666572726f2f66696c616d656e742d6f646f6d657465722d65617379) ](https://packagist.org/packages/gsferro/filament-odometer-easy)

Filament Odometer Easy
======================

[](#filament-odometer-easy)

> 🇧🇷 Português · 🇺🇸 [English](README.en.md)

Contadores animados para o **Filament v3, v4 e v5** — tabelas, infolists e widgets de estatísticas — do jeito mais simples possível: instale, registre o plugin e use.

É o mesmo efeito do contador **"Items found"** da página oficial [filamentphp.com/plugins](https://filamentphp.com/plugins), pronto para os seus dashboards e métricas em tempo real.

🎬 Demo
------

[](#-demo)

**`OdometerStat` no dashboard** — com `poll`, os contadores re-animam sozinhos a cada atualização de valor:

[![OdometerStat com polling](/art/OdometerStat.gif)](/art/OdometerStat.gif)

**`OdometerColumn` em tabelas** — animação no load, na ordenação e na troca de página:

[![OdometerColumn em tabela](/art/OdometerColumn.gif)](/art/OdometerColumn.gif)

**`OdometerEntry` em infolists e `OdometerNavigationBadge` em menus**:

[![OdometerEntry em infolist e navigation badge](/art/odometer.gif)](/art/odometer.gif)

Componentes
-----------

[](#componentes)

ComponenteEstendeUso`OdometerColumn``TextColumn`Colunas de tabela`OdometerEntry``TextEntry`Entries de infolist`OdometerStat``Stat`Counts no `StatsOverviewWidget``OdometerNavigationBadge`—Badge de navegação (`getNavigationBadge()`)Facade `FilamentOdometerEasy`—Qualquer view/blade customizadoTodos herdam **100% da API do componente base** (`sortable`, `searchable`, `label`, `description`, `color` etc.) — só o valor passa a ser animado.

Motores de animação (drivers)
-----------------------------

[](#motores-de-animação-drivers)

O pacote traz dois motores e você escolhe por config ou de forma fluente no plugin:

### `number-flow` — padrão ⭐

[](#number-flow--padrão-)

O web component [number-flow](https://github.com/barvian/number-flow) (usado pelo próprio site do Filament):

- ✅ **Zero dependências** — sem jQuery, sem CDN; o bundle (~16 KB) já vem no pacote
- ✅ **Anima do 0 no primeiro render** — exibe 0 e, após um delay configurável, anima até o valor
- ✅ **Re-anima a cada atualização** — perfeito com Livewire, `poll()` e dashboards em tempo real
- ✅ **Formatação nativa via `Intl.NumberFormat`** — moeda, decimais e locale (`pt-BR` → `1.000,00`)
- ✅ **Acessível** — respeita `prefers-reduced-motion`
- ✅ Mantido ativamente

### `odometer` — secundário

[](#odometer--secundário)

O efeito clássico do [odometer.js](https://github.com/HubSpot/odometer) via [gsferro/laravel-odometer-easy](https://github.com/gsferro/laravel-odometer-easy) (instalado como dependência):

- 🎨 7 temas visuais: `default`, `car`, `digital`, `minimal`, `plaza`, `slot-machine`, `train-station`
- ⚠️ Depende do jQuery (o plugin injeta automaticamente no `` dos painéis)
- ⚠️ Anima apenas na primeira renderização (não re-anima ao atualizar o valor)

Compatibilidade
---------------

[](#compatibilidade)

FilamentSuporteObservações**5.x**✅**4.x**✅**3.x** (3.2+)✅A mesma versão do pacote atende as três — o Composer resolve pela versão do Filament do seu projeto. Requer PHP 8.2+.

Instalação
----------

[](#instalação)

```
composer require gsferro/filament-odometer-easy
php artisan filament:assets
```

Registre o plugin no seu painel:

```
use Gsferro\FilamentOdometerEasy\FilamentOdometerEasyPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(FilamentOdometerEasyPlugin::make());
}
```

Pronto. ✨ Sem npm, sem publicar views, sem configurar assets — o driver `number-flow` já funciona.

Tip

A maioria das apps já roda `filament:assets` automaticamente no `post-autoload-dump`(via `filament:upgrade`). Nesse caso, basta o `composer require`.

Uso
---

[](#uso)

### Coluna de tabela

[](#coluna-de-tabela)

```
use Gsferro\FilamentOdometerEasy\Tables\Columns\OdometerColumn;

OdometerColumn::make('total_vendas')
    ->label('Total de vendas')
    ->sortable(),
```

### Entry de infolist

[](#entry-de-infolist)

```
use Gsferro\FilamentOdometerEasy\Infolists\Components\OdometerEntry;

OdometerEntry::make('total_vendas')
    ->label('Total de vendas'),
```

### Stat (StatsOverviewWidget)

[](#stat-statsoverviewwidget)

```
use Gsferro\FilamentOdometerEasy\Widgets\OdometerStat;

protected function getStats(): array
{
    return [
        OdometerStat::make('Total de vendas', Venda::count())
            ->description('Últimos 30 dias')
            ->descriptionIcon('heroicon-m-arrow-trending-up')
            ->color('success'),
    ];
}
```

Tip

Combine com `->poll('10s')` no widget: com o driver `number-flow`, o contador re-anima a cada atualização de valor. 📈

### Badge de navegação (menu do painel)

[](#badge-de-navegação-menu-do-painel)

```
use Gsferro\FilamentOdometerEasy\Navigation\OdometerNavigationBadge;

// no Resource (ou Page)
public static function getNavigationBadge(): ?string
{
    return OdometerNavigationBadge::make(static::getModel()::count());
}

// ou em um NavigationItem customizado
NavigationItem::make('Vendas')
    ->badge(fn (): string => OdometerNavigationBadge::make(Venda::count())),
```

A API de navegação do Filament só aceita `string` (HTML é escapado), então o componente envolve o valor com um marcador invisível e o JS do pacote troca o texto do badge por um `` animado. A formatação usa a config global do `number-flow` (`locales`, `format`, `delay`, `duration`).

Note

Disponível apenas no driver `number-flow`. No driver `odometer`, o valor é exibido como texto puro, sem animação.

### Em qualquer view (facade)

[](#em-qualquer-view-facade)

```
use Gsferro\FilamentOdometerEasy\Facades\FilamentOdometerEasy;

// driver configurado (number-flow por padrão)
FilamentOdometerEasy::render(1500);

// forçando um driver pontualmente
FilamentOdometerEasy::renderNumberFlow(1500, format: ['style' => 'currency', 'currency' => 'BRL']);
FilamentOdometerEasy::renderOdometer(1500, format: '(.ddd),dd', class: 'h3');
```

Formatação
----------

[](#formatação)

O método `->format()` está disponível em todos os componentes e aceita o formato do driver ativo:

```
// number-flow: array com opções do Intl.NumberFormat
OdometerColumn::make('receita')
    ->format(['style' => 'currency', 'currency' => 'BRL']),

OdometerStat::make('Conversão', $taxa)
    ->format(['style' => 'percent', 'minimumFractionDigits' => 1]),

// odometer: string data-format
OdometerColumn::make('receita')
    ->format('(.ddd),dd'),
```

### Velocidade da animação

[](#velocidade-da-animação)

Todos os componentes aceitam `->duration()` (driver number-flow; quanto maior, mais lento):

```
OdometerStat::make('Receita', $total)
    ->duration(2000), // conta em câmera lenta ✨
```

Referências: [opções do Intl.NumberFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#options) · [format do odometer](https://github.com/HubSpot/odometer#api).

Configuração
------------

[](#configuração)

### Fluente, direto no plugin

[](#fluente-direto-no-plugin)

```
FilamentOdometerEasyPlugin::make()
    ->locales('pt-BR')                                      // number-flow: 1.000,00
    ->format(['style' => 'currency', 'currency' => 'BRL'])  // padrão global
    ->delay(500)                                            // ms antes da animação inicial (0 → valor)
    ->duration(1500),                                       // velocidade da animação em ms (padrão ~900ms)
```

Para usar o motor clássico:

```
FilamentOdometerEasyPlugin::make()
    ->driver('odometer')
    ->theme('digital')          // default, car, digital, minimal, plaza, slot-machine, train-station
    ->format('(.ddd),dd')       // data-format padrão
    ->jquery(enabled: false),   // quando a aplicação já carrega o jQuery
```

### Ou pelo arquivo de config

[](#ou-pelo-arquivo-de-config)

```
php artisan vendor:publish --tag="filament-odometer-easy-config"
```

```
return [
    // number-flow (padrão) | odometer
    'driver' => 'number-flow',

    'number-flow' => [
        'locales' => null,  // ex.: 'pt-BR'; null usa o locale do navegador
        'format' => null,   // ex.: ['style' => 'currency', 'currency' => 'BRL']
        'delay' => 500,     // ms antes da animação inicial: exibe 0 e anima até o valor
        'duration' => null, // velocidade da animação em ms; null usa o padrão (~900ms)
    ],

    'odometer' => [
        'theme' => 'default',
        'format' => null,  // ex.: '(.ddd),dd'; null usa o padrão (pt-BR: 1.000,00)

        'jquery' => [
            'enabled' => true,
            'src' => 'https://code.jquery.com/jquery-4.0.0.min.js',
            'integrity' => 'sha256-OaVG6prZf4v69dPg6PhVattBXkcOWQB62pdZ3ORyrao=',
        ],
    ],
];
```

Como funciona por baixo dos panos
---------------------------------

[](#como-funciona-por-baixo-dos-panos)

- **number-flow**: o pacote já entrega o web component `` bundlado (`resources/dist/filament-odometer-easy.js`, registrado como ES module via `FilamentAsset`), o mesmo usado em filamentphp.com/plugins. A view Blade renderiza o elemento com `data-value`/`data-format`/`data-locales` e o bundle o inicializa: exibe 0, espera o `delay` e anima até o valor. Um `MutationObserver` acompanha as mudanças de `data-value`feitas pelo morph do Livewire (poll, refresh) e re-anima do valor atual para o novo — sem depender de `x-init`, que não roda de novo quando o Livewire preserva o elemento.
- **Navigation badge**: `getNavigationBadge()` e `NavigationItem::badge()` são tipados como `?string` e o Blade escapa o conteúdo, então não dá para retornar HTML. `OdometerNavigationBadge::make()` envolve o valor com `U+2060` (word joiner, invisível); o bundle detecta o marcador no `.fi-badge-label`, troca o texto por um ``e usa a config global exposta em `window.filamentOdometerEasy` por render hook. Quando o Livewire re-renderiza o badge, a animação parte do valor anterior (`data-start`).
- **odometer**: os assets (tema css, `odometer.js`, `odometer-easy.js`) são servidos direto do vendor do `gsferro/odometer-easy` via `FilamentAsset`, e o jQuery é injetado por render hook no `` dos painéis.
- A troca de driver seleciona quais assets são registrados — nunca os dois ao mesmo tempo.

Desenvolvimento
---------------

[](#desenvolvimento)

O bundle do number-flow só precisa ser regerado se você alterar `resources/js/index.js`:

```
npm install
npm run build
```

Testes
------

[](#testes)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](.github/CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](.github/SECURITY.md) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [gsferro](https://github.com/gsferro)
- [number-flow](https://github.com/barvian/number-flow) by Maxwell Barvian
- [odometer.js](https://github.com/HubSpot/odometer) by HubSpot
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance100

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

3

Last Release

0d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/9857d9f527903d58285b8afd4c9cc5d4150041a5951ba5b84c399d0e579b0255?d=identicon)[gsferro](/maintainers/gsferro)

---

Top Contributors

[![gsferro](https://avatars.githubusercontent.com/u/12704346?v=4)](https://github.com/gsferro "gsferro (12 commits)")

---

Tags

laravelanimationcounterdashboardfilamentfilament-pluginfilamentphpOdometergsferrofilament-odometer-easynumber-flow

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/gsferro-filament-odometer-easy/health.svg)

```
[![Health](https://phpackages.com/badges/gsferro-filament-odometer-easy/health.svg)](https://phpackages.com/packages/gsferro-filament-odometer-easy)
```

###  Alternatives

[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.8k](/packages/rawilk-profile-filament-plugin)[backstage/mails

View logged mails and events in a beautiful Filament UI.

16321.5k](/packages/backstage-mails)[marcelweidum/filament-passkeys

Use passkeys in your filamentphp app

6649.5k2](/packages/marcelweidum-filament-passkeys)[mradder/filament-logger

Audit logging, activity tracking, exports, alerts, and dashboards for Filament admin panels.

2318.8k](/packages/mradder-filament-logger)[caresome/filament-neobrutalism-theme

A neobrutalism theme for FilamentPHP admin panels

335.6k1](/packages/caresome-filament-neobrutalism-theme)[andreia/filament-ui-switcher

Add a modal with options to switch between different UI layouts and styles (colors, fonts, font sizes).

246.4k](/packages/andreia-filament-ui-switcher)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
