沃梦达 / 编程问答 / php问题 / 正文

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

Plot multiple graphs (Chart.js) from php loop for reading multiple files(从 php 循环中绘制多个图表(Chart.js)以读取多个文件)

本文介绍了从 php 循环中绘制多个图表(Chart.js)以读取多个文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been trying to plot multiple graphs with Chart.js from php loops. It turns out that Chart.js will only aglomerate the data within only one canvas (the first) ~ the others end up blank. I feel I'm close, but not quite there yet... Would please someone help me? Thanks in advance! And here's my code:

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

PS: The canvas spaces appear inside the other divs, although blank... So that's cleared.

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

这就是现在的结果...

This is how the result looks right now...

所有数据在第一个图中聚集在一起,而在第二个图中没有...

推荐答案

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

Well, turns out I came up with the solution to my problem, of course with a lot of help from stackoverflow and YouTube code friends. What this does is, based on the number of (two columns, no header ~ all can be adapted) comma separeted values files you have within a public storage url, it reads through each file and builds a Chart.js graph dynamically to each one of them. Anyhow... If it is of any help to anyone, here's my code and the sources of help that I used:

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

In the view blade file (created-project.blade.php), I've inserted the canvas and functions from Chart.js within the foreach loop, in order to run it through each file with data:

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

EDIT 1: The way it is here, data from the x axis will be treated as continuous (linear). But be sure to have added the script line from Chart.js correspondent to at least the 3.0.0-beta.7. On earlier versions, this won't work...

@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('
');

                    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 循环.没有添加,它会导致页面中的图表数量增加一倍.

PS: The reason for the var cont = cont + {!! $spectraCount !!} at the end of the for JavaScript loop is to match the number of counted files, and finish the for loop, which will restart again each time through the foreach loop from the blade code. That not beign added, it results in doubled number of charts in the page.

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

The data came through the livewire component (CreatedProject.php), holding the following code:

<?php

    namespace AppHttpLivewire;

    use LivewireComponent;
    use AppModelsSpectra;
    use IlluminateSupportFacadesDB;
    use IlluminateSupportFacadesHttp;

    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() 函数中处理,代码如下:

The files came into the database already being processed within the save() function in the livewire component (NewProject.php), with the folowing code:

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');

}

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

And, of course, you shouldn't forget to add the Chart.js main CDN script within the head tags of your HTML in the view file, or install it however you feel it's best.

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

Exemple result from two different text files:

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

PS2: My CSS is Tailwind based. Love it!

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

The main sources of help I had to solve it:

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

这篇来自 stackoverflow 的帖子:Multiple带有chart.js 的动态折线图|js和html

This post from stackoverflow: Multiple dynamic line charts with chart.js | Js and html

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

The video this guy made (not in English, but pretty much understandable): https://youtu.be/sjF7A_uMbgc

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

Issue answer from @etimberg in Chart.js Github: https://github.com/chartjs/Chart.js/issues/8233

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

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

All were right to the point, and with a few adjustments I've got it running. So, I leave here my thank you to the open code community!

这篇关于从 php 循环中绘制多个图表(Chart.js)以读取多个文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

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

基础教程推荐