DEV Community

Ariel Mejia
Ariel Mejia

Posted on • Updated on

Create charts in Laravel with eloquent and Larapex Charts

Alt Text

What is Larapex?

It is a Laravel package that provides a wrapper to create apexcharts with only PHP.

What we are going to build?

An eloquent example to create charts from eloquent queries

Lets start

First create a project

In valet

laravel new yourproject 
Enter fullscreen mode Exit fullscreen mode

With composer

composer create-project --prefer-dist laravel/laravel yourproject  
Enter fullscreen mode Exit fullscreen mode

Then add the LarapexChart Package

Go to your app directory and in your console/terminal/cmd/bash type:

composer require arielmejiadev/larapex-charts 
Enter fullscreen mode Exit fullscreen mode

About the project.

It will simulate a TODO app with users that creates TODOS, this tutorial will show all commands and code in every file, so just follow the steps.

I will create a TODO model and assign TODOS to users (with default User model from a fresh Laravel installation).

To create a model with migrations, factories and seeders you can use the flag "a" with the make model artisan command:

php artisan make:model Todo -a 
Enter fullscreen mode Exit fullscreen mode

The TODO Model file content will look like this:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Todo extends Model
{
    protected $fillable = [
        'title', 'state', 'user_id'
    ];

    protected $casts = [
        'status' => 'boolean',
    ];

    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Enter fullscreen mode Exit fullscreen mode

The User model file content:


namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function todos()
    {
        return $this->hasMany(Todo::class);
    }
} 
Enter fullscreen mode Exit fullscreen mode

The TODO migration file content:


use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateTodosTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('todos', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title');
            $table->boolean('status')->default(false);
            $table->unsignedBigInteger('user_id');
            $table->foreign('user_id')->references('id')->on('users');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('todos');
    }
}

Enter fullscreen mode Exit fullscreen mode

TODO Factory content:

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Todo;
use App\User;
use Faker\Generator as Faker;

$factory->define(Todo::class, function (Faker $faker) {
    return [
        'title'     => $faker->title,
        'status'    => $faker->boolean,
        'user_id'   => factory(User::class),
    ];
});
Enter fullscreen mode Exit fullscreen mode

The TODO Seeder content:


use App\User;
use App\Todo;
use Illuminate\Database\Seeder;

class TodoSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $userOne = factory(User::class)->create([
            'name' => 'John Doe'
        ]);

        $userTwo = factory(User::class)->create([
            'name' => 'Anne Doe'
        ]);

//        TODOS by this month

        factory(Todo::class, 15)->create([
            'user_id' => $userOne,
            'status' => true
        ]);

        factory(Todo::class, 20)->create(['user_id' => $userOne]);

        factory(Todo::class, 14)->create([
            'user_id' => $userTwo,
            'status' => true
        ]);

        factory(Todo::class, 23)->create(['user_id' => $userTwo]);

//        TODOS ONE MONTH AGO

        factory(Todo::class, 5)->create([
            'user_id' => $userOne,
            'status' => true,
            'created_at' => now()->subMonth()
        ]);

        factory(Todo::class, 10)->create(['user_id' => $userOne, 'created_at' => now()->subMonth()]);

        factory(Todo::class, 4)->create([
            'user_id' => $userTwo,
            'status' => true,
            'created_at' => now()->subMonth()
        ]);

        factory(Todo::class, 13)->create(['user_id' => $userTwo, 'created_at' => now()->subMonth()]);

//        TODOS TWO MONTHS AGO

        factory(Todo::class, 8)->create([
            'user_id' => $userOne,
            'status' => true,
            'created_at' => now()->subMonths(2)
        ]);

        factory(Todo::class, 16)->create(['user_id' => $userOne, 'created_at' => now()->subMonths(2)]);

        factory(Todo::class, 14)->create([
            'user_id' => $userTwo,
            'status' => true,
            'created_at' => now()->subMonths(2)
        ]);

        factory(Todo::class, 23)->create(['user_id' => $userTwo, 'created_at' => now()->subMonths(2)]);


    }
}

Enter fullscreen mode Exit fullscreen mode

Add Todo seeder

Go to database/seeds/DatabaseSeeders.php and add the Todo seeder in run method as the code below:

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Seed the application's database.
     *
     * @return void
     */
    public function run()
    {
        $this->call(TodoSeeder::class);
    }
} 
Enter fullscreen mode Exit fullscreen mode

Now run the migrations

Go to your terminal/console/bash/cmd and type the next commands:

php artisan migrate
php artisan db:seed
Enter fullscreen mode Exit fullscreen mode

Add a route

For this tutorial I will create a controller for charts, executing the artisan command:

php artisan make:controller ChartController
Enter fullscreen mode Exit fullscreen mode

Then go to routes/web.php and add the next route:

Route::get('chart', ChartController::class); 
Enter fullscreen mode Exit fullscreen mode
  • This controller will only have one method so in Route get method I can pass as second param the controller class and Laravel will load the __invoke method if it exists.

The controller content:


namespace App\Http\Controllers;

use App\Todo;
use App\User;
use ArielMejiaDev\LarapexCharts\Facades\LarapexChart;
use Illuminate\Http\Request;

class ChartController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {
        $user        = User::first();
        $userTwo     = User::find(2);
        $todosDone   = Todo::where('user_id', $user->id)->whereStatus(true)->count();
        $todosNotYet = Todo::where('user_id', $user->id)->whereStatus(false)->count();

        $chart = LarapexChart::setTitle('Your Todos Stats')
            ->setLabels(['Done', 'Not Yet'])
            ->setDataset([$todosDone, $todosNotYet]);


        return view('chart', compact('chart'));
    }


}

Enter fullscreen mode Exit fullscreen mode

Create a view file

Next is necesary to create a blade file to render the chart, go to resources/views and create a file called "chart.blade.php"

add the next code to your view:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Todos Chart</title>
</head>
<body>

    {!! $chart->container() !!}


    <script src="{{ $chart->cdn() }}"></script>
    {!! $chart->script() !!}

</body>
</html> 
Enter fullscreen mode Exit fullscreen mode

Now open your project

In the browser with your project basepath and "/chart" you will see:

Alt Text

Congrats! now you are implementing apex charts in your Laravel project.

More?

This is a simple example but, maybe you really want to create more complex charts, so go on this.

In your ChartController.php change the last content with this:

namespace App\Http\Controllers;

use App\Todo;
use App\User;
use ArielMejiaDev\LarapexCharts\Facades\LarapexChart;
use Illuminate\Http\Request;

class ChartController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {

        $user = User::first();
        $userTwo = User::find(2);

        $usercurrentMonthTodos = Todo::where('user_id', $user->id)->whereStatus(true)->whereMonth('created_at', '=', now()->month)->count();
        $userTodosAMonthAgo = Todo::where('user_id', $user->id)->whereStatus(true)->whereMonth('created_at', '=', now()->subMonth()->month)->count();
        $userTodosTwoMonthAgo = Todo::where('user_id', $user->id)->whereStatus(true)->whereMonth('created_at', '=', now()->subMonths(2)->month)->count();

        $userTwocurrentMonthTodos = Todo::where('user_id', $userTwo->id)->whereStatus(true)->whereMonth('created_at', '=', now()->month)->count();
        $userTwoTodosAMonthAgo = Todo::where('user_id', $userTwo->id)->whereStatus(true)->whereMonth('created_at', '=', now()->subMonth()->month)->count();
        $userTwoTodosTwoMonthAgo = Todo::where('user_id', $userTwo->id)->whereStatus(true)->whereMonth('created_at', '=', now()->subMonths(2)->month)->count();

        $chart = LarapexChart::setType('line')
            ->setLabels([$user->name, $userTwo->name])
            ->setXAxis(['Now', 'A month ago', '2 months ago'])
            ->setDataset([
            [
                'username' => $user->name,
                'data' => [
                    $usercurrentMonthTodos, $userTodosAMonthAgo, $userTodosTwoMonthAgo
                ]
            ],
            [
                'username' => $userTwo->name,
                'data' => [
                    $userTwocurrentMonthTodos, $userTwoTodosAMonthAgo, $userTwoTodosTwoMonthAgo
                ]
            ]
        ]);


        return view('chart', compact('chart'));
    }


} 
Enter fullscreen mode Exit fullscreen mode

This will load a line chart with two different series of data

Alt Text

You can change the value in setType() method to add this types:

  • area
  • bar
  • heatmap

You can even change the colors of the chart by adding the method setColors(), to the chart instance like this:

$chart = LarapexChart::setType('line')
            ->setLabels([$user->name, $userTwo->name])
        ->setXAxis(['Now', 'A month ago', '2 months ago'])
        ->setColors(['#ffc73c', '#f5746f'])
Enter fullscreen mode Exit fullscreen mode

To get more examples and documentation of LarapexCharts go to LarapexCharts Documentation site

Top comments (29)

Collapse
 
lancelotcs profile image
lance du Toit

Hi @arielmejiadev, Thanks for the package, I'm pretty new with Laravel, but managed to get your charts working well with my MSSQL database, the issue I'm trying to overcome or understand is how can we put multiple charts on one view. I have tried to create components and bring them to my main dashboard, but It seems I can only have one at a time displaying, what am I missing here?
PS-I hope you enjoyed the coffee on me.

Collapse
 
arielmejiadev profile image
Ariel Mejia

Hi @lancelotcs hehe thanks! the package allows to use CLI to generate chart classes so you would be able to add multiple charts through the view/js component, you can add an issue in the github repository with your current code so I am going to be able to reproduce it.

Collapse
 
lancelotcs profile image
lance du Toit

Hi, thanks for the quick response, I managed to get it to work, I changed my controller to inject (not sure if correct word) both charts into one function, then sent both charts to the view in the array. My issue was I had 2 functions in 1 controller and 2 routes to same location and controller calling 2 different functions, only one of these would work at any given time.

Is there a list of the return functions in the chart like setTitle(),setSubtitle(),setColors(),setLabels(),etc?

Image description
Image description

Collapse
 
haiderlatitude profile image
Haider Ali • Edited

Hi @arielmejiadev. Firstly, thanks for a great package for creating charts. I've used your package in my laravel project and it worked like a breeze, however, I think I have found a bug. Let me demonstrate;

So the thing is, I first created a pie chart exactly like you mentioned and it worked perfectly. However, I then changed the type of the chart from "pie" to "line", but when I changed the type, the method "setLabels()" stopped working. Instead of setting our custom labels for the chart it just states "series-1" and "series-2".

Then I again changed the type from "line" to "bar" and tried setting the labels on that type of chart, but only to find out it again sets the labels on that chart "series-1" and "series-2".

Then I tried to completely remove the labels but again, in vain. The labels don't get removed either, but stay there having the values "series-1" and "series-2".

Please fix this bug.

Thank you.

Collapse
 
arielmejiadev profile image
Ariel Mejia

Hi Haider thanks for using the package... I am currently working on my free time on updating the docs site... I will try to check... if you could add an issue in the package repository would be great.

Are you using the blade integration? or the Vue/Inertia integration?

I would be glad to check this as soon as possible, just take in mind that it is something that I usually check on weekends.

Collapse
 
junedchhipa profile image
Juned Chhipa

Great work there.

Would you mind if I add the link of Larapex in the main ApexCharts.js repository? I would also like to add an intro page of Larapex to the docs section of the website (similar to apexcharts.com/docs/react-charts/) so that people willing to use ApexCharts with Laravel finds it easily.

Cheers

Collapse
 
arielmejiadev profile image
Ariel Mejia

Let me know if you need something more, thanks for taking the time to check it

Collapse
 
arielmejiadev profile image
Ariel Mejia

Of course it would be awesome it would be very nice

Collapse
 
arielmejiadev profile image
Ariel Mejia

Hi Juned just to tell you that the apexcharts.com site is broken, greetings!

Collapse
 
alexv96 profile image
alexv96

Hi question how can I format it as a thousands separator ? for example I have tried all the php number_format money_format options and I have this number 41598625 and in the graph it only shows me 4.159 or sometimes it doesn't make up a number nothing to do.

I made the query from the DB already brought with the number format that I want but when I pass it to the graph the format disappears.

Collapse
 
masterinho52 profile image
Julio

Hi Ariel,

Great job, greetings from Xela, this package looks very easy to use, i will give it a try and let you know how it goes!

Just for records, the documentation site is broken : arielmejiadev.github.io/LarapexCha...

Best!

Collapse
 
arielmejiadev profile image
Ariel Mejia

Hi yep I was updated the new version of the package and the documentation just today I release the 1.0.5 version, if you give a try now it will load, thanks You are from Guatemala right? please share with other cool Laravel artisans I am from Guatemala too there are Laravel devs?

Collapse
 
jhondona profile image
jhondona

Good day sir. I was trying to view the documentation but since it is broken at the moment, I will just ask here if it is possible or is there a parameter I can use to add a link on the chart ? thank you. Btw, I really like this package. Great work.

Collapse
 
arielmejiadev profile image
Ariel Mejia

Sorry, a few day ago I release the version 2 of the package and I updated the documentation site the link is now updated, hope you enjoy it!

Collapse
 
jolexc profile image
jolexC

Hi Ariel,

Thank you for this Larapex... Really appreciate it.
I would like to try the heatmap. Do you have an example for this type of Chart where I can explore in?

Thanks

Collapse
 
arielmejiadev profile image
Ariel Mejia

Here an online example using Larapex & Tailwindcss larapex-chart-example.herokuapp.com/ and for a specific heatmap: here is the package docs with an example of heatmap and other chart types with blade or VueJS components with inertia: larapex-charts.netlify.app/more-ch...

Collapse
 
jolexc profile image
jolexC

Thanks for the quick reply.

I am sorry for the confusion. I mean, do have sample of chart heatmap overlay a map. Like map of US with number of voters per State, Color coded, with % and figures showing when the mouse is scroll per state. Thanks

Thread Thread
 
arielmejiadev profile image
Ariel Mejia

Sorry I did not do that before, the package works behind the scenes with apexcharts.js, so you would need to check if there is an example with that but as far as I can remember I never saw something like this, sorry.

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
kevind170 profile image
kevind170

Hi Ariel
Brilliant work!
Quick question, is it possible to produce Mixed Charts?
If so, could you point me in the right direction
Many thanks

Collapse
 
arielmejiadev profile image
Ariel Mejia

Sorry at this moment the package only support non mixed charts, because I handle a standard object on the backend and I the mixed charts would have a lot of different structures, it could be something to work on the future, but at this moment the package only has this types:

  • Pie
  • Donut
  • Radial
  • Polar area
  • Line
  • Area
  • Bar
  • Horizontal Bar
  • Heatmap
  • Radar
Collapse
 
nowodev profile image
Favour • Edited

You're a life saver 💪 💪 💪

Collapse
 
arielmejiadev profile image
Ariel Mejia

Hehe hope it helps!

Collapse
 
zaratedev profile image
Jonathan Zarate

Hi, Ariel.

This is a good work!

I hope to contribute very soon.

Collapse
 
arielmejiadev profile image
Ariel Mejia

Sure why not, Thanks for taking the time to check the package, please if you have a comment feel free to write about it, do you already use it?

Some comments may only be visible to logged-in visitors. Sign in to view all comments.