图表控件Flot改造

本文详细介绍了如何对Flot JavaScript图表插件进行定制化改造,包括背景区域绘制、根据数据点颜色变化、批量绘制控制图、时间轴格式调整及换批提示线的添加。改造后的插件能够更好地适应特定的控制图绘制需求。
 
 
 

 

不得不说,flot算是一个精巧的js绘制图表的插件。原型类似上图。下面列出一些API

网上有很多介绍其API的文章,有兴趣可以去cnblogs.com上去搜搜。目前,这个只是实现了,点线,区域图形,以及饼图,柱状图的绘制。一般情况下做一点简单的应用时可以的。但是,现在需要将其改造成另一个样子。

              背景区域绘制

              可以描点,并且可以根据不同点的数据,将点绘制为不同的颜色。

              根据数据序列的不同,以及数据序列的个数,绘制多张不同的控制图。传入几个数据序列绘制几张图。

              数据序列只是一个数组,横坐标为时间,纵坐标为值。纵坐标只显示UCLCLlCL三个数值

              多张控制图时,只有最后一张控制图显示时间横轴。

              只有第一张图需要根据数据点值的不同,设置点的颜色。

              ToolTips需要用数组传入,不使用其拼字符串的形式。

              小批换批时,根据传入的换批时间绘制换批提示线。

改造后效果为:

 

 

 

  绘制背景区域。

首先,影藏其网格线。需要将其源代码中drawGrid()方法的,绘制网格线部分注释掉。第1680到1764行。

它原有的绘制背景的方法,我们不适用,并且重写其方法。增加方法function drawBackground(options){}参数是innit时传入的options。

方法代码:

          var top=ticks[2];

          var center=ticks[1];

          var bottom=ticks[0];

          var percent=plotHeight/(max-min);

       

 

         //第一个空白区域高度为00到max-top

         var area1=(max-top)*percent;

           ctx.fillStyle = "#F8F8FF";

           ctx.fillRect(0, 0, plotWidth, area1);

 

             ctx.strokeStyle = "#696969";

             ctx.lineWidth = 0.5;//0, area3, plotWidth, smalltoparea

             ctx.moveTo(0, area1);

             ctx.lineTo(plotWidth, area1);

           //第二个区域为:area1到area2加上,(top-center)/3

           var smalltoparea=((top-center)/3)*percent;

              ctx.fillStyle = "rgb(250, 188, 186)";

                ctx.fillRect(0, area1, plotWidth, smalltoparea);

            //第三个区域

            var area2=2*smalltoparea;

              ctx.fillStyle = "rgb(251, 254, 188)";

           ctx.fillRect(0, area2, plotWidth, smalltoparea);

           // 第四个区域

         var area3=3*smalltoparea;

              ctx.fillStyle = "rgb(209, 254, 214)";

           ctx.fillRect(0, area3, plotWidth, smalltoparea);

           //CL下面每一个小区域高度

           var smallbottomarea=((center-bottom)/3)*percent;

           var area4=4*smalltoparea;

 

                        ctx.strokeStyle = "#696969";

                        ctx.lineWidth = 0.5;//0, area3, plotWidth, smalltoparea

                        ctx.moveTo(0, area4);

                        ctx.lineTo(plotWidth, area4);

                    

              ctx.fillStyle = "rgb(209, 254, 214)";

           ctx.fillRect(0, area4, plotWidth, smallbottomarea);

 

             var area5=area4+smallbottomarea;

              ctx.fillStyle = "rgb(251, 254, 188)";

           ctx.fillRect(0, area5, plotWidth, smallbottomarea);

 

 

           var area6=area5+smallbottomarea;

           ctx.fillStyle = "rgb(250, 188, 186)";

           ctx.fillRect(0, area6, plotWidth, smallbottomarea);

 

         

 

            var area7=area6+smallbottomarea;

             ctx.fillStyle = "#F8F8FF";

             ctx.fillRect(0, area7, plotWidth, smallbottomarea);

             ctx.strokeStyle = "#696969";

             ctx.lineWidth = 0.5;//0, area3, plotWidth, smalltoparea

             ctx.moveTo(0, area7);

             ctx.lineTo(plotWidth, area7);

                        ctx.stroke();

                          ctx.restore();

   

}

 

填充区域时,其小坐标原点在绘图区域左上角。需要根据比例算出需要在小坐标中绘制背景的高度。背景分为八个区,从坐标(0,0)点高度依次叠加。在draw()方法中调用drawbackground(options)方法。// if (!options.grid.backgroundImage) ctx.clearRect(0, 0, canvasWidth, canvasHeight);

        //   ctx.clearRect(0, 0, canvasWidth, canvasHeight);

 

            var grid = options.grid;

 

            // draw background, if any

            //if (grid.show && grid.backgroundColor)

                drawBackground(options);

绘制表格,绘制背景,绘制数据序列都在draw()方法中调用。

二、描点,根据不同的数据将点绘制为不同的颜色。后台根据不同的判异规格,将数据点序列判异后,返回一个与数据点一一对应的数组。数组中保存数据点是否被判异。不判异的点为0,判异的点位1。所有为0的点都使用正常颜色,为1的点使用红色。源代码从2124行开始。

   function drawSeriesPoints(series) {

            function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol,ispoint) {

                var points = datapoints.points, ps = datapoints.pointsize;

                //复制 产生新的ColorIndex数组

                var ColorArry=[];

                if (series.colorIndex!=null&&series.colorIndex.length>0) {

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

    ColorArry.push(series.colorIndex[i]);

     ColorArry.push(series.colorIndex[i]);

//由于每个points都包含两个坐标轴的数据,先x轴,后y轴。一一对应的数据也需要成对出现

}

   

}

             

                for (var i = 0; i < points.length; i += ps) {

                    var x = points[i], y = points[i + 1];

                  //                    if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)

//                        continue;

                         if (x == null || x < axisx.min || x > axisx.max )//超出x轴的数据不绘图

                        continue;

                    //超出最大值的点,在绘制时将其值设为最大值,不会改变原有数据

                    if (y < axisy.min ) {

                          y= axisy.min ;

                            }

                    if (y > axisy.max) {

                           y=axisy.max;

                            }

                    

                    ctx.beginPath();

                    x = axisx.p2c(x);

                    y = axisy.p2c(y) + offset;

                    if (symbol == "circle")

                        ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);

                    else

                        symbol(ctx, x, y, radius, shadow);

                    ctx.closePath();

                    if (ColorArry[i]==1) {

                        ctx.fillStyle = "#FF0000";

                        ctx.strokeStyle="#FF0000";

                        ctx.fill();

                     

}

else {

       if (fillStyle) {

                        ctx.fillStyle =  series.color;

                        ctx.fill();

                    }

}

                

                    ctx.stroke();

 

                    if (ispoint) {

     ctx.strokeStyle=   series.color;

}

                  

                }

            }

           

            ctx.save();

            ctx.translate(plotOffset.left, plotOffset.top);

 

            var lw = series.points.lineWidth,

                sw = series.shadowSize,

                radius = series.points.radius,

                symbol = series.points.symbol;

            if (lw > 0 && sw > 0) {

                // draw shadow in two steps

                var w = sw / 2;

                ctx.lineWidth = w;

                ctx.strokeStyle = "rgba(0,0,0,0.1)";

                plotPoints(series.datapoints, radius, null, w + w/2, true,

                           series.xaxis, series.yaxis, symbol,false);

 

                ctx.strokeStyle = "rgba(0,0,0,0.2)";

                plotPoints(series.datapoints, radius, null, w/2, true,

                           series.xaxis, series.yaxis, symbol,false);

            }

 

            ctx.lineWidth = lw;

            ctx.strokeStyle = series.color;

            plotPoints(series.datapoints, radius,

                       getFillStyle(series.points, series.color), 0, false,

                       series.xaxis, series.yaxis, symbol,true);

            ctx.restore();

        }

 

我们改变了最大值点的绘制,原本如果数据点超出最大值时,是不绘制点的。此时我们将超出最大值的点的值设为最大值。那么,还需要更改其亮点之间的连接线。

方法为:(源代码1867行开始)

 

            function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {

                var points = datapoints.points,

                    ps = datapoints.pointsize,

                    prevx = null, prevy = null;

               

                ctx.beginPath();

                for (var i = ps; i < points.length; i += ps) {

                    var x1 = points[i - ps], y1 = points[i - ps + 1],

                        x2 = points[i], y2 = points[i + 1];

                   

                    if (x1 == null || x2 == null)

                        continue;

 

                    // clip with ymin

                    if (y1 <= y2 && y1 < axisy.min) {

                        if (y2 < axisy.min)

                        y2=axisy.min;

                          //  continue;   // line segment is outside

                        // compute new intersection point

                       // x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;

                        y1 = axisy.min;

                    }

                    else if (y2 <= y1 && y2 < axisy.min) {

                        if (y1 < axisy.min)

                        y1=axisy.min;

                          //  continue;

                       // x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;

                        y2 = axisy.min;

                    }

 

                    // clip with ymax

                    if (y1 >= y2 && y1 > axisy.max) {

                        if (y2 > axisy.max)

                        y2=axisy.max;

                         //   continue;

                       // x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;

                        y1 = axisy.max;

                    }

                    else if (y2 >= y1 && y2 > axisy.max) {

                        if (y1 > axisy.max)

                        y1=axisy.max;

                         //   continue;

                       // x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;

                        y2 = axisy.max;

                    }

 

                    // clip with xmin

                    if (x1 <= x2 && x1 < axisx.min) {

                        if (x2 < axisx.min)

                            continue;

                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;

                        x1 = axisx.min;

                    }

                    else if (x2 <= x1 && x2 < axisx.min) {

                        if (x1 < axisx.min)

                            continue;

                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;

                        x2 = axisx.min;

                    }

 

                    // clip with xmax

                    if (x1 >= x2 && x1 > axisx.max) {

                        if (x2 > axisx.max)

                            continue;

                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;

                        x1 = axisx.max;

                    }

                    else if (x2 >= x1 && x2 > axisx.max) {

                        if (x1 > axisx.max)

                            continue;

                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;

                        x2 = axisx.max;

                    }

 

                    if (x1 != prevx || y1 != prevy)

                        ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);

                   

                    prevx = x2;

                    prevy = y2;

                    ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);

                }

                ctx.stroke();

            }

 

        

由于先前绘制时,超出最大值的数据不绘制,所以当数据移到修改后的点时也不会显示ToolTip

源码2439行   function findNearbyItem(mouseX, mouseY, seriesFilter) 方法中,需要将超出最大值的数据点设为最大值。

2470行增加几行代码

                     if (y < axisy.min ) {

                        y= axisy.min ;

                             }

                        if (y > axisy.max) {

                              y=axisy.max;

                              }

 

然后直接获取数据位置,取其y值

function showTooltip(x, y, contents) {

 

 

        var ev = document.onmousemove;

        var mousePos = mousePosition(ev);

        y = mousePos.y;

        $('<div id="tooltip">' + contents + '</div>').css({

            position: 'absolute',

            display: 'none',

            top: y + 5,

            left: x + 5,

            border: '1px solid #fdd',

            padding: '2px',

            'background-color': '#fee',

            opacity: 0.80

        }).appendTo("body").fadeIn(200);

    }

 

获取鼠标位置:

function mousePosition(ev){

    var x, y;

    var ev = ev || window.event;

    return {

        x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,

        y:ev.clientY + document.body.scrollTop  - document.body.clientTop

    };

}

 

三、根据数据序列个数不同,绘制不同张数的控制图。目前Spc控制图最多有三张,至少有1长。所以将绘制方法包装一下即可。

所有的数据序列,时间,自定义的tooltips等都已参数传入。并计算其最大最小值。最没有技术的就是这个部分….

function DrawChart(chartcount, spec1, spec2, spec3, data1, reddotArry, data2, data3, timeArry, batchChangeTime, Tips1, Tips2, Tips3, placeholder1, placeholder2, placeholder3) {

    var d1 = [];

    var d2 = [];

    var d3 = [];

    var changeTime = [];

    var maxspec1 = 0;

    var minspec1 = 0;

    var specMaxLength

    if (spec1 != null && spec1.length > 0) {

        maxspec1 = spec1[2] + (spec1[2] - spec1[1]) / 3;

        minspec1 = spec1[0] -(spec1[1] - spec1[0]) / 3;

    }

    var maxspec2 = 0;

    var minspec2 = 0;

    if (spec2 != null && spec2.length > 0) {

        maxspec2 = spec2[2] + (spec2[2] - spec2[1]) / 3;

        minspec2 = spec2[0] - (spec2[1] - spec2[0]) / 3;

    }

    var maxspec3 = 0;

    var minspec3 = 0;

    if (spec3 != null && spec3.length > 0) {

        maxspec3 = spec3[2] + (spec3[2] - spec3[1]) / 3;

        minspec3= spec3[0] - (spec3[1] - spec3[0]) / 3;

    }

 

 

 

 

    if (timeArry != null && timeArry.length > 0) {

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

            d1.push([GetTimeStep(new Date(timeArry[i])), data1[i]]);

        }

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

            d2.push([GetTimeStep(new Date(timeArry[i])), data2[i]]);

        }

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

            d3.push([GetTimeStep(new Date(timeArry[i])), data3[i]]);

        }

    }

 

 

    if (batchChangeTime != null && batchChangeTime.length>0) {

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

            changeTime.push(GetTimeStep(new Date(batchChangeTime[i])));

        }

    }

 

    if (chartcount == 1 || (placeholder2 == "" && placeholder3 == "")) {

        DrawLastChart(spec3, maxspec3, minspec3, d3, changeTime, Tips3, reddotArry, placeholder3, timeArry);

        $(placeholder1).hide();

        $(placeholder2).hide();

    }

    else if (chartcount == 2 || placeholder3 == "") {

        plot3 = DrawLastChart(spec3, maxspec3, minspec3, d3, changeTime, Tips3, null, placeholder3);

        DrawFirstChart(spec1, maxspec1, minspec1, d1, changeTime, Tips1, reddotArry, placeholder1,plot3);

     

        $(placeholder2).hide();

    }

    else if (chartcount == 3) {

       plot2= DrawCenterChart(spec2, maxspec2, minspec2, d2, changeTime, Tips2, placeholder2);

       plot3= DrawLastChart(spec3, maxspec3, minspec3, d3, changeTime, Tips3, null, placeholder3);

        DrawFirstChart(spec1, maxspec1, minspec1, d1, changeTime, Tips1, reddotArry, placeholder1,plot2,plot3);

      

    }

    else {

        placeholder1.hide();

        placeholder2.hide();

        placeholder3.hide();

    }

 

 

}

 

然后调用绘制控制图的方法即可。第一张图:需要根据数据点的不同标红。第二张:不需要横坐标。但是数据要与第一张图一一对应。第三张图:需要横坐标,而且第三张图,有时需要当第一张图使用。所以需要三种绘图方法。DrawFirstChart();DrawCenterChart();DrawLastChart();

具体代码在后面贴出。

三张图数据点的一一对应。

  三张图的绘制时间是一致的。即同一时间会在三张图中绘制三个点。此时,如果不做处理,绘制出来的数据是有偏移的——与时间不能对应。有两种方式,可以设置坐标轴的小数点位置,但是会出现以下情况:

0.0000或者,23.1220与3.1200的位置依旧有偏移。

 固定左边坐标轴位置:擦,还要改源码

877行  function measureTickLabels(axis)方法中修改923行

                if (labels.length > 0) {

                    dummyDiv = makeDummyDiv(labels, "");

                    if (w == null)

                    w=40;

                       // w = dummyDiv.children().width();

                    if (h == null)

                        h = dummyDiv.find("div.tickLabel").height();

                    dummyDiv.remove();

                }

将w设置为固定宽度。同时修改背景绘制区域的起始位置,否则坐标轴会被绘制在背景区域中。

修改228行  checkload()方法

function checkload() {

              if(options.grid.backgroundImage)

                     if ( bgimage.complete ) {               

                            ctx.save();

                            ctx.restore();

             

                 var pp = ctx.createPattern(bgimage, 'repeat');

                 ctx.fillStyle = pp;

                 ctx.fillRect(45, 0, canvasWidth-47, canvasHeight);

                   draw();

            }

                     else

                            setTimeout( checkload, 100 ) ;

       }

 

 

 

四:y轴可以直接设置yaxis: { ticks: spec ,min:minspec,max:maxspec},

但是x轴的时间需要先转换为UTC再放到数组中。2012/4/12 12:12:12格式转换为UTC代码为

function GetTimeStep(time) {

    day = time.getHours();

 

    time = time.setHours(8 + day);

 

    time = new Date(time);

 

    time = time.getTime();

 

    return time;

 

}

五、只有最后一张显示时间横轴,

  xaxis: { mode: "time", timeformat: "%h:%M", minTickSize: [1, "minute"], show: false },

把不需要x轴的控制图show:FALSE即可。

 

7,切换批次时,根据传入的换批时间绘制换批提示线。增加方法

 

function drawBatchChangeLine(series){

            ctx.save();

            ctx.translate(plotOffset.left, plotOffset.top);

            var axisx=series.xaxis;

            var axisy=series.yaxis;

             var ticks=axisy.ticks;

              var max=axisy.max;

              var min=axisy.min;

              var changeTime=series.BatchChangeTime;

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

                   ctx.moveTo(axisx.p2c(changeTime[i]) , 0);

                    ctx.lineTo(axisx.p2c(changeTime[i]) , plotHeight );

             ctx.stroke();

                       

 

 

}

            

           

                //ctx.stroke();

                   ctx.restore();

        }

该方法在drawSeries()时被调用

 

  function drawSeries(series) {

            if (series.lines.show)

                drawSeriesLines(series);

            if (series.bars.show)

                drawSeriesBars(series);

            if (series.points.show)

                drawSeriesPoints(series);

                drawBatchChangeLine(series);

        }

 

到此,改造基本结束

 

 

 

图中黑线为换批线。红色的竖线为校准线,会随鼠标移动而移动。

 

 

转载于:https://www.cnblogs.com/hexinxiaoyao/archive/2012/05/24/hx1.html

AI 代码审查Review工具 是一个旨在自动化代码审查流程的工具。它通过集成版本控制系统(如 GitHub 和 GitLab)的 Webhook,利用大型语言模型(LLM)对代码变更进行分析,并将审查意见反馈到相应的 Pull Request 或 Merge Request 中。此外,它还支持将审查结果通知到企业微信等通讯工具。 一个基于 LLM 的自动化代码审查助手。通过 GitHub/GitLab Webhook 监听 PR/MR 变更,调用 AI 分析代码,并将审查意见自动评论到 PR/MR,同时支持多种通知渠道。 主要功能 多平台支持: 集成 GitHub 和 GitLab Webhook,监听 Pull Request / Merge Request 事件。 智能审查模式: 详细审查 (/github_webhook, /gitlab_webhook): AI 对每个变更文件进行分析,旨在找出具体问题。审查意见会以结构化的形式(例如,定位到特定代码行、问题分类、严重程度、分析和建议)逐条评论到 PR/MR。AI 模型会输出 JSON 格式的分析结果,系统再将其转换为多条独立的评论。 通用审查 (/github_webhook_general, /gitlab_webhook_general): AI 对每个变更文件进行整体性分析,并为每个文件生成一个 Markdown 格式的总结性评论。 自动化流程: 自动将 AI 审查意见(详细模式下为多条,通用模式下为每个文件一条)发布到 PR/MR。 在所有文件审查完毕后,自动在 PR/MR 中发布一条总结性评论。 即便 AI 未发现任何值得报告的问题,也会发布相应的友好提示和总结评论。 异步处理审查任务,快速响应 Webhook。 通过 Redis 防止对同一 Commit 的重复审查。 灵活配置: 通过环境变量设置基
【直流微电网】径向直流微电网的状态空间建模与线性化:一种耦合DC-DC变换器状态空间平均模型的方法 (Matlab代码实现)内容概要:本文介绍了径向直流微电网的状态空间建模与线性化方法,重点提出了一种基于耦合DC-DC变换器的状态空间平均模型的建模策略。该方法通过数学建模手段对直流微电网系统进行精确的状态空间描述,并对其进行线性化处理,以便于系统稳定性分析与控制器设计。文中结合Matlab代码实现,展示了建模与仿真过程,有助于研究人员理解和复现相关技术,推动直流微电网系统的动态性能研究与工程应用。; 适合人群:具备电力电子、电力系统或自动化等相关背景,熟悉Matlab/Simulink仿真工具,从事新能源、微电网或智能电网研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握直流微电网的动态建模方法;②学习DC-DC变换器在耦合条件下的状态空间平均建模技巧;③实现系统的线性化分析并支持后续控制器设计(如电压稳定控制、功率分配等);④为科研论文撰写、项目仿真验证提供技术支持与代码参考。; 阅读建议:建议读者结合Matlab代码逐步实践建模流程,重点关注状态变量选取、平均化处理和线性化推导过程,同时可扩展应用于更复杂的直流微电网拓扑结构中,提升系统分析与设计能力。
内容概要:本文介绍了基于物PINN驱动的三维声波波动方程求解(Matlab代码实现)理信息神经网络(PINN)求解三维声波波动方程的Matlab代码实现方法,展示了如何利用PINN技术在无需大量标注数据的情况下,结合物理定律约束进行偏微分方程的数值求解。该方法将神经网络与物理方程深度融合,适用于复杂波动问题的建模与仿真,并提供了完整的Matlab实现方案,便于科研人员理解和复现。此外,文档还列举了多个相关科研方向和技术服务内容,涵盖智能优化算法、机器学习、信号处理、电力系统等多个领域,突出其在科研仿真中的广泛应用价值。; 适合人群:具备一定数学建模基础和Matlab编程能力的研究生、科研人员及工程技术人员,尤其适合从事计算物理、声学仿真、偏微分方程数值解等相关领域的研究人员; 使用场景及目标:①学习并掌握PINN在求解三维声波波动方程中的应用原理与实现方式;②拓展至其他物理系统的建模与仿真,如电磁场、热传导、流体力学等问题;③为科研项目提供可复用的代码框架和技术支持参考; 阅读建议:建议读者结合文中提供的网盘资源下载完整代码,按照目录顺序逐步学习,重点关注PINN网络结构设计、损失函数构建及物理边界条件的嵌入方法,同时可借鉴其他案例提升综合仿真能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值