gpt4 book ai didi

javascript - 使用旧数据重新创建图表

转载 作者:行者123 更新时间:2023-12-03 16:52:30 25 4
gpt4 key购买 nike

我使用了JSF 2.2,Primefaces 6.0,CDI和Highcharts 4.2.3。我的页面之一包含一张图表(Highcharts)和一个干扰我图表的简单表格。我剪切了代码(请看下面),向您展示代码中最重要的部分。

我想实现这样的目标:

  • 当我在表单中按commandButton时,图表应使用新数据重新创建。

  • 到目前为止,我已经:
  • 在脚本中的函数中声明了几个js变量;
  • 创建了一个createChart函数,该函数使用#{bean.getDataForChart1a(typeOfData)}从CDI bean(实际上是从数据库)下载数据(对于我的图表),并将这些数据放入js变量中。除了下移数据外,该函数还创建图表。
  • 创建了一个createNewChart函数,该函数销毁了我当前的图表,并调用createChart函数来创建应包含新数据的新图表。

  • 问题是最后阶段。在下面的 View 中,我已经将 oncomplete="createNewChart();"属性添加到了 commandButton中,此刻,我的页面如下所示:
  • 打开页面时,一切正常。下载数据并创建图表。
  • 当我按commandButton时,将重新创建图表,但它使用的是旧数据。我注意到createChart函数中没有再次下载数据,js没有执行#{bean.getDataForChart1a(typeOfData)}。因此,#{bean.getDataForChart1a(typeOfData)}在开始时仅执行一次。我不明白为什么。

  • 如何解决此问题?

    我的xhtml页面:
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://primefaces.org/ui"
    xmlns:pt="http://xmlns.jcp.org/jsf/passthrough"
    xmlns:pe="http://primefaces.org/ui/extensions">

    <h:head>
    <!-- loading css -->
    </h:head>

    <h:body>

    <div id="container" style="height: 750px; width: 100%; margin: 0 auto;"/>

    <script type="text/javascript">

    //<![CDATA[

    var chart;

    var protos;
    var dataChart;
    var color;

    var seriesChart;
    var i, len;

    function createChart() {

    //Downloading data for the chart
    protos = #{visualizationController.getDataForChart1a("protos")};
    dataChart = #{visualizationController.getDataForChart1a("data")};
    color = #{visualizationController.getDataForChart1a("color")};

    seriesChart = [];

    //Creating several series of the data
    for (i = 0, len = protos.length; i < len; i++) {

    seriesChart.push({
    color: color[i],
    name: protos[i],
    data: dataChart[i]
    //other options
    });
    }

    console.time('scatter');
    console.time('asyncRender');

    Highcharts.setOptions({
    lang: {
    //translate
    }
    });

    // Create the chart
    chart = new Highcharts.Chart({

    //other options

    chart: {

    //other options
    renderTo: "container"
    },

    series : seriesChart
    });

    console.timeEnd('scatter');

    }

    function createNewChart(){

    chart.destroy();
    createChart();
    }

    createChart();

    //]]>
    </script>

    <h:form id="filterForm">

    <p:selectManyCheckbox id="filter" value="#{visualizationController.selectedKindOfNetwork}" layout="responsive" columns="4">
    <p:ajax update="filterButton" />
    <f:selectItems value="#{visualizationController.kindOfNetwork}" var="kindOfNetwork" itemLabel="#{kindOfNetwork}" itemValue="#{kindOfNetwork}" />
    </p:selectManyCheckbox>

    <br/>

    <p:commandButton id="filterButton" value="Filtruj" action="#{visualizationController.actionFilterButtonForChart1a()}"
    disabled="#{!visualizationController.visibilityFilterButtonForChart1a}"
    update="filterForm"
    oncomplete="createNewChart();"/>

    </h:form>

    </h:body>
    </html>

    最佳答案

    我已经达到了预期的结果。基于@SiMag的评论,我发布了答案,其中包括几种可能的解决方案。帖子分为几个部分,使您可以了解我做错了什么以及为解决此问题所做的事情。

    我做错什么了?

    就像@SiMag写道:

    The script tag isn't updated after the first load so the #{visualizationController.getData...} expressions aren't evaluated anymore and they are referring to the old data.



    我到底是什么问题?

    此刻,当我知道自己做错了什么时,正确的问题是:
  • 如何将几个值从CDI bean传递到javascript?
  • 如何在服务器或客户端调用javascript函数(将就绪数据和必需数据传递给此函数)?


  • 我的页面应该如何工作?

    这是您必须知道的最后一个问题,以了解我将在下一部分中进行的操作。我的页面应如下所示:
  • 加载/打开页面时,应执行createChart javascript函数(自动执行,无需任何按钮或链接),并且该函数应使用我在CDI bean中设置的多个值。作为此操作的结果,应显示该图表。
  • 每次按下按钮时,应执行changeData javascript函数,并且该函数应使用在CDI bean中设置的几个值。作为此操作的结果,图表应更新其显示的数据。

  • 如果您想实现其他目标,那不是问题。根据您在这里可以找到的解决方案,您将能够实现所需的解决方案。

    第一个解决方案

    第一种解决方案基于:
  • 通过RequestContext将一些值从CDI bean传递到javascript。为了实现这一点,我基于素语表documentation (第11.1章RequestContext);
  • 在服务器端调用createChart函数;
  • 在客户端调用changeChart函数。

  • 首先,我在javascript函数中添加了三个参数(对于每个要从CDI bean传递到javascript代码的值,每个参数一个)。此刻,脚本应如下所示:
    <script type="text/javascript">

    //<![CDATA[

    var chart;

    var protos;
    var dataChart;
    var color;

    var seriesChart;
    var i, len;

    //Creating the chart.
    function createChart(protosArg, dataArg, colorsArg) {

    $(function() {

    //The data are parsed
    protos = JSON.parse(protosArg);
    dataChart = eval(dataArg);
    colors = JSON.parse(colorsArg);

    seriesChart = [];

    //Creating several series of the data
    for (i = 0, len = protos.length; i < len; i++) {

    seriesChart.push({
    color: color[i],
    name: protos[i],
    data: dataChart[i]
    //other options
    });
    }

    console.time('scatter');
    console.time('asyncRender');

    Highcharts.setOptions({
    lang: {
    //translate
    }
    });

    // Create the chart
    chart = new Highcharts.Chart({

    //other options

    chart: {

    //other options
    renderTo: "container"
    },

    series : seriesChart
    });

    console.timeEnd('scatter');
    });
    }

    //Updating the chart using the new supplied data.
    function changeData(protosArg, dataArg, colorsArg){

    $(function() {

    protos = JSON.parse(protosArg);
    dataChart = eval(dataArg);
    colors = JSON.parse(colorsArg);

    seriesChart = [];

    //Creating several series of the data using the new supplied data.
    for (i = 0, len = protos.length; i < len; i++) {

    seriesChart.push({
    color: color[i],
    name: protos[i],
    data: dataChart[i]
    //other options
    });
    }

    //Removing the old data from the chart.
    for (i = 0, len = chart.series.length; i < len; i++) {

    chart.series[0].remove(false);
    }

    //Inserting the new data to the chart.
    for (i = 0, len = protos.length; i < len; i++) {

    chart.addSeries(seriesChart[i],false);
    }

    chart.redraw();

    });
    }

    //]]>
    </script>

    让我们继续到服务器。在这里,我向您展示我的数据的样子。在服务器端,我创建了三个 String变量。在服务器端,此变量的输出如下所示:
  • 原型(prototype):["tcp","udp",...]
  • 数据:[[[date,23],[date,1234]],[[date,1234]]]
  • 颜色:["black","white",...]

  • 上面的样子,我使用 JSON.parse()eval()方法保存传递的数据。为什么?由于浏览器将传递的数据解释为字符串,因此我们必须将数据转换为数组。

    在服务器端,我还使用 RequestContext#addCallbackParam()方法创建了几个回调参数。 getProtos()getData()getColors()方法返回带有我准备好的数据的字符串。
    requestContext = RequestContext.getCurrentInstance();
    requestContext.addCallbackParam("protosArg", getProtos());
    requestContext.addCallbackParam("dataArg", getData());
    requestContext.addCallbackParam("colorsArg", getColors());

    最后,我调用 RequestContext#execute()方法,该方法调用 createChart javascript函数并传递三个必需值:
        @PostConstruct
    public void init() {

    //Creating the callback parameters.
    initData();

    requestContext.execute(String.format("createChart('%s', '%s', '%s')", getProtos(),getData(),getColors()));
    }

    请注意,,我已使用 ''字符在javascript端实现了正确的表示。目前,浏览器会将数据解释为字符串。我在CDI bean的 execute()方法(具有 init()批注)中调用 @PostConstruct方法,因此,我确定:
  • createChart javascript函数在开始时仅执行一次(CDI bean具有@ViewScoped批注);
  • 将准备在脚本中下载的数据。

  • 我在客户端完成的最后一件事是:更改 oncomplete组件的 <p:commandButton>属性的值。 oncomplete属性调用 changeData javascript函数。 args参数引用我在服务器端设置的回调参数。
    <p:commandButton id="filterButton" value="Filter" action="#{chart2Controller.actionFilterButton()}"
    disabled="#{!chart2Controller.visibilityFilterButton}"
    update="filterForm"
    oncomplete="changeData(args.protosArg, args.dataArg, args.colorsArg);"/>

    我的CDI bean的一部分:
    @Named
    @ViewScoped
    public class Chart2Controller implements Serializable {

    /**
    * Start method.
    */
    @PostConstruct
    public void init() {

    //Creating the callback parameters.
    initData();

    requestContext.execute(String.format("createChart('%s', '%s', '%s')", getProtos(),getData(),getColors()));
    }

    /**
    * Downloading the data from the database.
    */
    private void initData(){


    /*
    * Sending the query to the database including the filter options of the form,
    * saving the result and preparing the data basing on the result.
    */

    //Preparing the callback parameters.
    requestContext = RequestContext.getCurrentInstance();
    requestContext.addCallbackParam("protos", protos);
    requestContext.addCallbackParam("data", data);
    requestContext.addCallbackParam("colors", colors);
    }

    /**
    * Action for the filter button.
    */
    public void actionFilterButton(){

    initData();
    }

    /**
    * Visibility for filter button.
    */
    public boolean getVisibilityFilterButton(){
    //return true or false.
    }

    //Getter and Setter

    private static final long serialVersionUID = -8128862377479499815L;

    @Inject
    private VisualizationService visualizationService;

    private RequestContext requestContext;

    private List<String> kindOfNetwork;
    private List<String> selectedKindOfNetwork;

    private String protos;
    private String data;
    private String colors;
    }

    第二解决方案

    第二种解决方案基于:
  • 通过RequestContext将一些值从CDI bean传递到javascript;
  • 在客户端调用createChart函数;
  • 在客户端调用changeChart函数。

  • 看起来,该解决方案与先前的解决方案相似,但是 createChart函数正在调用的位置不同。在这种情况下,我在客户端调用了 createChart,并使用EL从CDI bean提供值。

    我不会重复代码,因此仅告诉您为实现预期结果所做的工作。在服务器端,除了调用 RequestContext#execute()方法外,我已经完成了与以前的解决方案相同的操作。取而代之的是,我在脚本结尾处在客户端调用了 createChart函数。该脚本应如下所示:
    <script type="text/javascript">

    //<![CDATA[

    var protos;
    var dataChart;
    var color;

    //other code


    //Creating the chart.
    function createChart(protosArg, dataArg, colorsArg) {

    $(function() {

    protos = protosArg;
    dataChart = dataArg;
    colors = colorsArg;

    //other code
    });
    }

    //Updating the chart using the new supplied data.
    function changeData(protosArg, dataArg, colorsArg){

    $(function() {

    //The data are parsed
    protos = JSON.parse(protosArg);
    dataChart = eval(dataArg);
    colors = JSON.parse(colorsArg);

    //other code
    });
    }

    createChart(#{chart2Controller.protos}, #{chart2Controller.data}, #{chart2Controller.colors});

    //]]>
    </script>

    请注意,,我还从 JSON.parse()函数中删除了 eval()createChart方法,因为EL已直接写入javascript代码,并且浏览器将数据正确解释为数组。

    第三种解决方案

    第三种解决方案基于:
  • 通过<h:inputHidden>组件将一些值从CDI bean传递到javascript;
  • 在客户端调用createChart函数;
  • 在客户端调用changeChart函数。

  • 此解决方案完全不同。一开始,我在表单中添加了三个 <h:inputHidden> componenet(每个要传递给javascript的值一个)。该表格应如下所示:
    <h:form id="filterForm">

    <h:inputHidden id="protos" value="#{chart2Controller.protos}" />
    <h:inputHidden id="data" value="#{chart2Controller.data}" />
    <h:inputHidden id="colors" value="#{chart2Controller.colors}" />

    <p:selectManyCheckbox id="filter" value="#{chart2Controller.selectedKindOfNetwork}" layout="responsive" columns="4">
    <p:ajax update="filterButton" />
    <f:selectItems value="#{chart2Controller.kindOfNetwork}" var="kindOfNetwork" itemLabel="#{kindOfNetwork}" itemValue="#{kindOfNetwork}" />
    </p:selectManyCheckbox>

    <br/>

    <p:commandButton id="filterButton" value="Filtruj" action="#{chart2Controller.actionFilterButton()}"
    disabled="#{!chart2Controller.visibilityFilterButton}"
    update="filterForm"
    oncomplete="changeData();"/>

    </h:form>

    上面的样子,我添加了 idvalue<h:inputHidden>属性,并将所需的数据保存在 value属性中。

    请注意,,当您按下按钮时,表单会更新(请查看 update组件的 <p:commandButton>属性),因此,我确定每次按下时,都会下载输入的 value属性中的数据按钮。

    最后,我已经通过 document.getElementById("filterForm:idOfInput").value在javascript代码中引用了这些值。请记住使用 JSON.parse()eval(),因为数据被解释为字符串。该脚本应如下所示:
    <script type="text/javascript">

    //<![CDATA[

    var chart;

    var protos;
    var dataChart;
    var colors;

    function createChart() {

    $(function() {

    protos = JSON.parse(document.getElementById("filterForm:protos").value);
    dataChart = eval(document.getElementById("filterForm:data").value);
    colors = JSON.parse(document.getElementById("filterForm:colors").value);

    //other code
    });
    }

    function changeData(){

    $(function() {

    protos = JSON.parse(document.getElementById("filterForm:protos").value);
    dataChart = eval(document.getElementById("filterForm:data").value);
    colors = JSON.parse(document.getElementById("filterForm:colors").value);

    //other code
    });
    }

    //]]>
    </script>

    高图并更改图表数据

    就我而言,我不知道每次按下按钮后会得到多少系列数据,因此有可能每次我都会获得不同系列的数据。 Highcharts API不支持这种情况。您可以在循环中结合使用 Chart.addSeries()Series.setData()Series.remove()方法。如果还有更多时间,我会做,然后更新此答案。您可以在下面找到一些重新创建/更新图表的方法。

    如果您不知道数据序列号。

    第一个解决方案

    如果您不知道要获得多少数据序列(例如在我的情况下),则可以使用 Series.remove()删除当前数据序列,然后通过 Chart.addSeries()添加新的数据序列:
    function changeData(...){

    //Preparation of the received data.

    //Removing the old data from the chart.
    for (i = 0, len = chart.series.length; i < len; i++) {

    chart.series[0].remove(false);
    }

    //Inserting the new data to the chart.
    for (i = 0, len = protos.length; i < len; i++) {

    chart.addSeries(seriesChart[i],false);
    }

    chart.redraw();
    }

    注意,由于效率高,我为 false参数设置了 redraw。 Highcharts API说:

    If doing more operations on the chart, it is a good idea to set redraw to false and call chart.redraw() after.



    第二解决方案

    您还可以销毁图表并重新创建它。在这种情况下,您还必须像这样更改 changeData javascript函数:
    function changeData(...){

    chart.destroy();
    createChart(...);
    }

    如果您知道数据序列号。

    这种情况比前一种情况容易。看下面的代码,不需要任何解释:
    function changeData(...){

    //Preparation of the received data.

    for(var i = 0; i < chart.series.length; i++){

    chart.series[i].setData(seriesData[i],false);
    }

    chart.redraw();
    }

    关于javascript - 使用旧数据重新创建图表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38463938/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com