从 php 循环中绘制多个图表(Chart.js)以读取多个文件

Posted

技术标签:

【中文标题】从 php 循环中绘制多个图表(Chart.js)以读取多个文件【英文标题】:Plot multiple graphs (Chart.js) from php loop for reading multiple files 【发布时间】:2022-01-06 04:21:32 【问题描述】:

我一直在尝试使用来自 php 循环的 Chart.js 绘制多个图表。事实证明,Chart.js 只会将数据聚集在一个画布(第一个)中~其他的最终都是空白的。我觉得我很接近了,但还没有完全到那里......请有人帮助我吗?提前致谢!这是我的代码:

PS:画布空间出现在其他 div 中,虽然是空白的......所以这已经被清除了。

GraphPage.blade.php

@foreach ($items as $item)
<div class="table">
  <div class="table-row">
     $item->id 
  </div>
  <div class="table-row">
     $item->name 
  </div>
  <div class="table-row">
    <canvas class="bar-chart"></canvas>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
    <script type="text/javascript">
    
      <?php
      $i = 0;
      $files = fopen("storage/" . $item->file, "r");
      while(!feof($files)) 
      $content = fgets($files);
      $carray = explode(",", $content);
      list($axisX, $axisY) = $carray;
      $x[] = $axisX;
      $y[] = $axisY;
      $i++;
      
      fclose($files);

      $x_to_json = json_encode((array)$x);
      $y_to_json = json_encode((array)$y);
      ?>

      var x = <?php echo $x_to_json ?>;
      var y = <?php echo $y_to_json ?>;

      var ctx = document.getElementsByClassName('bar-chart');
      var chartGraph = new Chart(ctx, 
        type: 'bar',
        data: 
          labels: x,
          datasets: [
            label: "Bar Plot",
            data: y,
          ]
        
      );
    </script>
  </div>
</div>
@endforeach

这就是现在的结果...

All data aglomerated together in the first plot and nothing in the second...

【问题讨论】:

【参考方案1】:

好吧,事实证明我想出了解决问题的方法,当然,这得益于 *** 和 YouTube 代码朋友的大力帮助。它的作用是,根据公共存储 url 中的逗号分隔值文件的数量(两列,没有标题 ~ 都可以调整),它会读取每个文件并为每个文件动态构建 Chart.js 图表其中。无论如何......如果它对任何人有任何帮助,这是我的代码和我使用的帮助来源:

view Blade 文件 (created-project.blade.php) 中,我在 foreach 循环中插入了来自 Chart.js 的画布和函数,在为了通过每个带有数据的文件运行它:

编辑 1: 在这里,来自 x 轴 的数据将被视为连续(线性)。但请确保已将 Chart.js 对应的脚本行添加到至少 3.0.0-beta.7。在早期版本中,这将不起作用...

@foreach ($mols as $mol)
    <div class="flex flex-wrap m-1 w-5/6 lg:w-3/6">
        <script>

            var cont;
            for(cont = 0; cont < !! $spectraCount !!; cont++) 

                window.addEventListener('load', setup);

                async function setup() 

                    const ctx = document.getElementById('myChart').insertAdjacenthtml("afterend","<canvas id='canvas"+cont+"' height='230'></canvas>");
                    const can_id="canvas"+cont;
                    const ctx2 = document.getElementById(can_id).getContext('2d');
                    const spectra = await getData();

                    window.can_id = new Chart(ctx2, 

                        type: 'bar',
                        data: 
                            datasets: [
                                label: "!! $mol->nome_molecula !!",
                                backgroundColor: "#0070bf",
                                data: spectra.xy,
                                barThickness: 3,
                            ]
                        ,
                        options: 
                            scales: 
                                x: 
                                    type: 'linear',
                                    offset: false,
                                    gridLines: 
                                        offsetGridLines: false,
                                    
                                
                            
                        

                    );

                    window.can_id.update();

                

                async function getData() 
                    const response = await fetch('spectra/!! $mol->espectro !!');
                    const data = await response.text();
                    const xy = [];
                    const table = data.split('\n');

                    table.forEach(row => 
                        const columns = row.split(',');
                        xy.push('x': parseFloat(columns[0]), 'y': parseFloat(columns[1]));
                    );

                    return  xy ;

                

                var cont = cont + !! $spectraCount !!;

            

        </script>

        <canvas id="myChart" class="w-2 h-2"></canvas>

    </div>
@endforeach

PS:var cont = cont + !! for JavaScript 循环结束时的 $spectraCount !! 是为了匹配计数的文件数,并完成 for 循环,该循环将再次重新启动每次通过刀片代码中的 foreach 循环。没有添加,它会导致页面中的图表数量增加一倍。

数据来自livewire 组件 (CreatedProject.php),包含以下代码:

<?php

    namespace App\Http\Livewire;

    use Livewire\Component;
    use App\Models\Spectra;
    use Illuminate\Support\Facades\DB;
    use Illuminate\Support\Facades\Http;

    class CreatedProject extends Component
    
        public function render()
        
            $metadados = DB::table('new_projects')->where('user_id', '=', auth()->user()->id)->orderBy('id_projeto', 'DESC')->first();
            $mols = DB::table('new_molecules')->where('nome_projeto', '=', $metadados->nome_projeto)->get();
            $spectra = DB::table('spectras')->where('nome_projeto', '=', $metadados->nome_projeto)->get();
            $collection = collect($spectra);
            $spectraCount = collect($spectra)->count();

            return view('livewire.created-project', [
                'metadados' => $metadados,
                'mols' => $mols,
                'collection' => $collection,
                'spectraCount' => $spectraCount,
            ]);

        
    

进入数据库的文件已经在 livewire 组件 (NewProject.php) 中的 save() 函数中处理,代码如下:

public function save()

    foreach ($this->espectro as $key => $value) 

        $mol_localpath = $this->espectro[$key]->storeAs('spectra', $mol_path);

        $a = 0;
        $files = fopen("spectra/" . $this->espectro[$key]->hashName(), "r");
        while(!feof($files)) 
            $content = fgets($files);
            $carray = explode(",", $content);
            list($mz1, $int1) = $carray;
            $mz[] = $mz1;
            $int[] = $int1;
            $a++;
        

        fclose($files);

        Spectra::create([
            'user_id' => auth()->user()->id,
            'nome_projeto' => $this->nome_projeto,
            'espectro' => $this->espectro[$key]->hashName(),
            'mz' => $mz,
            'int' => $int,
        ]);

        $mz = [];
        $int = [];

    

    return redirect()->route('created-project');


当然,您不应该忘记将 Chart.js 主 CDN 脚本添加到视图文件中 HTML 的 head 标记中,或者按照您认为最好的方式安装它。

来自两个不同文本文件的示例结果:

PS2:我的 CSS 是基于 Tailwind 的。喜欢它!

我必须解决它的主要帮助来源:

这个系列来自 YouTube 上的 The Coding Train:https://youtu.be/RfMkdvN-23o

这篇来自***的帖子:Multiple dynamic line charts with chart.js | Js and html

这个人制作的视频(不是英文,但很好理解):https://youtu.be/sjF7A_uMbgc

Chart.js Github 中@etimberg 的问题答案:https://github.com/chartjs/Chart.js/issues/8233

他解释的小提琴:https://jsfiddle.net/ob0xc5u7/

一切都是正确的,经过一些调整,我已经开始运行了。所以,我要感谢开放代码社区!

【讨论】:

以上是关于从 php 循环中绘制多个图表(Chart.js)以读取多个文件的主要内容,如果未能解决你的问题,请参考以下文章

在 Django 模板中使用 for 循环显示多个 chart.js 图表

在Django模板中使用for循环显示多个chart.js图表

Chart.js 数据数组使用 PHP、MySQL。如何从 JSON 数组定义数据源?

使用 Chart.js 绘制图表,其中填充了每个 JsonRPC 获取的数据

Angular 10 - Chart.js 在运行时使用 convas id 在数组中绘制图表

在 v2 上的 chart.js 中的图表上绘制水平线