首页 > 解决方案 > Symfony 5 如何使用 jQuery ui 标签显示多个 Google 图表

问题描述

我的第一次 Symfony 5 尝试,我第一次尝试使用 Google Charts。我正在使用 CMENGoogleChartsBundle,它提供了一个 Twig 扩展和 PHP 对象来显示图表。

我想显示应该可以通过 jQuery UI 选项卡访问的不同图表我还有一个表格,其中显示了所有数据。例如,现在单击带有国家/地区的选项卡时,我希望更新图表和表格。我试图直接在我的树枝模板(fruitsoverview.html.twig)中显示所有数据,但是当单击一个选项卡时,我会在选项卡下方再次呈现页面,而且我会丢失任何可能的搜索过滤器设置,如果整个页面将被重新加载。然后我读到你可以只使用需要更新的内容创建一个视图,所以我已经这样做了,在我的控制器中我现在有:

if ($request->isXmlHttpRequest())
{

return $this->render('fruits/chart.html.twig', [
        'searchFilter' => $searchFilter->createView(),
        'fruitCounts' => $fruitCounts,
        'barchart' => $barchart
        ]);
}else{

    return $this->render('fruits/fruitsoverview.html.twig', [
        'searchFilter' => $searchFilter->createView(),
        'fruitCounts' => $fruitCounts,
        'barchart' => $barchart
        ]);
}}

这解决了渲染问题,但未显示图表。图表数据在树枝视图中可用,但图表仅显示在默认选项卡上。我确实让表格显示了正确的数据。什么可能是错误的或更好的问题,它应该如何正确设置。我确信我还没有理解 Symfony 的概念,可能还没有理解 jQuery ui Tabs。任何帮助将不胜感激。非常感谢您提前。

更新

我现在已经更新了我的代码,并且除了条形图之外还可以部分工作。因此,表格的树枝变量在 AJAX 请求之后使用新内容进行更新,但条形图不会改变。我已经
在 chart.html.twig 中完成了 {{ dump(barchart) }} 并且我确实在其中得到了更新的数据,但图表没有重新绘制。我怎样才能做到这一点?

控制器

    if ($request->isXmlHttpRequest())
    {         
        $response = new JsonResponse();
        $response->setStatusCode(200);
        return new JsonResponse([
                'html' => $this->renderView('fruits/chart.html.twig', [ 
                    'fruitCounts' => $fruitCounts,
                    'barchart' => $barchart
                    ])     
                ]);

在我的主模板中,我有以下代码和 Javascript。$("div#client-loop-container").html(data.html); 似乎更新了我的 chart.twig 模板中的 twig 变量。

   <div id="client-loop-container">
     {% include 'chart.html.twig' %}
   </div>


     {% block javascripts %}
        {{ encore_entry_script_tags('app') }}

     <script type="text/javascript">

     $( function() {

     $('#country-tabs a').on('click', function (e) {
        e.preventDefault()
        $(this).tab('show');
        var $this = $(this),
        loadurl = $this.attr('href');

        var form = $('form');

        var jsonData = $.ajax({
            url: loadurl,  
            type:       'POST',
            data: form.serializeArray(),
            dataType:   'json',  

            success: function(data, status) {  

               $("div#client-loop-container").html(data.html);  
            }
          }).responseText;
        });

图表.html.twig

    <div id="client-loop-container">
    <div class="w-100" id="div_chart"></div>

        <table class="table">
            <tr>
                <th>Date</th>
                {% for fruitcount in fruitcounts %}
                    <th>{{ fruitcount }} </th>
                {% endfor %}
            </tr>
        </table>
    </div>

        {% block javascripts %}

         <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
        <script type="text/javascript">
          {{ gc_draw(barchart, 'div_chart') }}          
        </script>

       {% endblock %}

标签: symfonyjquery-uisymfony5

解决方案


这是一个可能的解决方案。下面的代码使用单个<div>来显示图表,但您可能能够适应选项卡和id="..."解决方案。该方法用于jQuery.getScript()运行特定于图表的 javascript。ChartService 使用 cmen/google-charts-bundle来生成 javascript。该脚本由控制器响应提供给显示模板。可以显示六种不同的图表。该页面以伪轮播样式显示图表。

您可能会问,既然可以一次绘制所有六个图表并使用 javascript 一次隐藏和显示一个图表,那么为什么要这么麻烦。答案是图表 2 - n 通常不会显示所有选项。我开发了这个解决方案,以便垂直轴始终显示网格线上的值。

ChartService(为简洁起见,删除了图表定义):

namespace App\Service;

use App\Entity\RV;
use App\Entity\Summary;
use CMEN\GoogleChartsBundle\GoogleCharts\Options\VAxis;
use CMEN\GoogleChartsBundle\GoogleCharts\Charts\Histogram;
use CMEN\GoogleChartsBundle\GoogleCharts\Charts\LineChart;
use CMEN\GoogleChartsBundle\Twig\GoogleChartsExtension;
use Doctrine\ORM\EntityManagerInterface;

class ChartService
{

    private $em;
    private $gce;

    public function __construct(EntityManagerInterface $em, GoogleChartsExtension $gce)
    {
        $this->em = $em;
        $this->gce = $gce;
    }

    public function buildChart($chartType, $class, $subtype = null)
    {
        switch ($chartType) {
            case 'line':
                return $this->lineChart($class, $subtype);
                break;
            case 'histogram':
                return $this->histoChart($class);
            default:
                break;
        }
    }

    private function lineChart($class, $type)
    {
...
        return $chart;
    }

    private function histoChart($class)
    {
...
        return $histo;
    }

    public function getChartJs($chartSpecs, $location)
    {
        $chartType = $chartSpecs['type'] ?? null;
        $class = $chartSpecs['class'] ?? null;
        $subtype = $chartSpecs['subtype'] ?? null;

        $chart = $this->buildChart($chartType, $class, $subtype);

        $js = $this->getStart($chart, $location);
        $end = $this->getEnd($chart, $location);
        $part3 = substr($end, 0, strlen($end) - 1);

        return $js . $end;
    }

    private function getStart($chart, $location)
    {
        return $this->gce->gcStart($chart, $location);
    }

    private function getEnd($chart, $location)
    {
        return $this->gce->gcEnd($chart, $location);
    }

}

chartSwitch.js

$(document).ready(function () {
    var i = $('#currentChart').attr('data-chart');
    chartSwitch(i);

    $('#chartNext').on('click', function () {
        i++;
        if (6 === i) {
            i = 0;
        }
        chartSwitch(i);
    });

    $('#chartPrevious').on('click', function () {
        i--;
        if (-1 === i) {
            i = 5;
        }
        chartSwitch(i);
    });

    function chartSwitch(i) {
        $('#currentChart').attr('data-chart', i);
        var url = "/js/" + i;
        $.getScript(url);
    }
});

控制器方法/js/ + i


    /**
     * @Route("/js/{which}", name="js")
     */
    public function returnChartJs(ChartService $chart, $which)
    {
        $available = [
            ['type' => 'line', 'class' => 'C', 'subtype' => 'Price'],
            ['type' => 'line', 'class' => 'C', 'subtype' => 'Count'],
            ['type' => 'line', 'class' => 'B+', 'subtype' => 'Price'],
            ['type' => 'line', 'class' => 'B+', 'subtype' => 'Count'],
            ['type' => 'histogram', 'class' => 'C'],
            ['type' => 'histogram', 'class' => 'B+'],
        ];

        $js = $chart->getChartJs($available[$which], 'chartA');
        $response = new Response($js);

        return $response;
    }

显示模板的相关部分:

        <div class="col-9 text-center">
            <div class="row">
                <div class="col-3"></div>
                <div class="col-3">
                    <span id="currentChart" data-chart="0"></span>
                    <nav aria-label="Page navigation">
                        <ul class="pagination">
                            <li class="page-item">
                                <a id="chartPrevious" class="page-link" href="#" aria-label="Previous">
                                    <span aria-hidden="true">&laquo; Chart</span>
                                    <span class="sr-only">Previous</span>
                                </a>
                            </li>
                            <li class="page-item">
                                <a id="chartNext" class="page-link" href="#" aria-label="Next">
                                    <span aria-hidden="true">Chart &raquo;</span>
                                    <span class="sr-only">Next</span>
                                </a>
                            </li>
                        </ul>
                    </nav>
                </div>            
            </div>
            <div class="row">
                <div class="col-12">
                    <div id="chartA"></div>
                </div>
            </div>
        </div>
...
{% block javascripts %}
    {{ parent() }}
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    {{ encore_entry_script_tags('charts') }}
{% endblock %}

推荐阅读