D3.js实现双曲线示波器

news/2024/7/10 1:38:10 标签: vue, node.js, d3.js, js

先上效果图
D3实现双曲线波形图
项目需要做一个显示不同波形的示波器,所以研究了一下D3,代码放一下,便于自己温习,有需要的可以自行学习。(欢迎指正);项目环境为vue项目中在node环境下,使用d3实现

this.padding = {top: -10, right: 10, bottom: 120, left: 40};

//坐标data大致这个形式
this.data[0].gainVal = [{"x":0,"y":439},{"x":1,"y":17},{"x":2,"y":799},{"x":3,"y":751},{"x":4,"y":484},{"x":5,"y":587},{"x":6,"y":491},{"x":7,"y":82},{"x":8,"y":730},{"x":9,"y":668},{"x":10,"y":769},{"x":11,"y":316},{"x":12,"y":486},{"x":13,"y":750},{"x":14,"y":305},{"x":15,"y":804},{"x":16,"y":377},{"x":17,"y":824},{"x":18,"y":802},{"x":19,"y":219},{"x":20,"y":65},{"x":21,"y":157},{"x":22,"y":576},{"x":23,"y":310},{"x":24,"y":452},{"x":25,"y":765},{"x":26,"y":705},{"x":27,"y":597},{"x":28,"y":788},{"x":29,"y":248},{"x":30,"y":651},{"x":31,"y":314},{"x":32,"y":412},{"x":33,"y":390},{"x":34,"y":45},{"x":35,"y":245},{"x":36,"y":698},{"x":37,"y":672},{"x":38,"y":648},{"x":39,"y":86},{"x":40,"y":220},{"x":41,"y":825},{"x":42,"y":368},{"x":43,"y":301},{"x":44,"y":271},{"x":45,"y":395},{"x":46,"y":159},{"x":47,"y":756},{"x":48,"y":236},{"x":49,"y":733},{"x":50,"y":488},{"x":51,"y":168},{"x":52,"y":525},{"x":53,"y":782},{"x":54,"y":366},{"x":55,"y":219},{"x":56,"y":218},{"x":57,"y":746},{"x":58,"y":412},{"x":59,"y":770},{"x":60,"y":290},{"x":61,"y":466},{"x":62,"y":258},{"x":63,"y":275},{"x":64,"y":108},{"x":65,"y":186},{"x":66,"y":557},{"x":67,"y":516},{"x":68,"y":168},{"x":69,"y":71},{"x":70,"y":140},{"x":71,"y":673},{"x":72,"y":653},{"x":73,"y":414},{"x":74,"y":238},{"x":75,"y":193},{"x":76,"y":755},{"x":77,"y":535},{"x":78,"y":207},{"x":79,"y":13},{"x":80,"y":126},{"x":81,"y":340},{"x":82,"y":631},{"x":83,"y":123},{"x":84,"y":681},{"x":85,"y":170},{"x":86,"y":147},{"x":87,"y":224},{"x":88,"y":224},{"x":89,"y":273},{"x":90,"y":342},{"x":91,"y":153},{"x":92,"y":86},{"x":93,"y":266},{"x":94,"y":53},{"x":95,"y":714},{"x":96,"y":470},{"x":97,"y":338},{"x":98,"y":304},{"x":99,"y":498}]
toolPage.js?7fd9:146 [{"x":0,"y":792},{"x":1,"y":595},{"x":2,"y":523},{"x":3,"y":541},{"x":4,"y":189},{"x":5,"y":528},{"x":6,"y":780},{"x":7,"y":70},{"x":8,"y":281},{"x":9,"y":821},{"x":10,"y":667},{"x":11,"y":453},{"x":12,"y":654},{"x":13,"y":75},{"x":14,"y":113},{"x":15,"y":190},{"x":16,"y":708},{"x":17,"y":796},{"x":18,"y":809},{"x":19,"y":714},{"x":20,"y":85},{"x":21,"y":498},{"x":22,"y":392},{"x":23,"y":718},{"x":24,"y":327},{"x":25,"y":112},{"x":26,"y":615},{"x":27,"y":824},{"x":28,"y":268},{"x":29,"y":776},{"x":30,"y":404},{"x":31,"y":385},{"x":32,"y":25},{"x":33,"y":16},{"x":34,"y":344},{"x":35,"y":551},{"x":36,"y":342},{"x":37,"y":344},{"x":38,"y":464},{"x":39,"y":335},{"x":40,"y":286},{"x":41,"y":604},{"x":42,"y":634},{"x":43,"y":479},{"x":44,"y":159},{"x":45,"y":285},{"x":46,"y":46},{"x":47,"y":568},{"x":48,"y":769},{"x":49,"y":404},{"x":50,"y":24},{"x":51,"y":500},{"x":52,"y":388},{"x":53,"y":717},{"x":54,"y":532},{"x":55,"y":608},{"x":56,"y":759},{"x":57,"y":460},{"x":58,"y":762},{"x":59,"y":96},{"x":60,"y":721},{"x":61,"y":259},{"x":62,"y":698},{"x":63,"y":126},{"x":64,"y":732},{"x":65,"y":377},{"x":66,"y":435},{"x":67,"y":18},{"x":68,"y":73},{"x":69,"y":554},{"x":70,"y":53},{"x":71,"y":626},{"x":72,"y":494},{"x":73,"y":595},{"x":74,"y":595},{"x":75,"y":259},{"x":76,"y":787},{"x":77,"y":432},{"x":78,"y":674},{"x":79,"y":168},{"x":80,"y":384},{"x":81,"y":232},{"x":82,"y":367},{"x":83,"y":626},{"x":84,"y":672},{"x":85,"y":790},{"x":86,"y":59},{"x":87,"y":604},{"x":88,"y":42},{"x":89,"y":692},{"x":90,"y":397},{"x":91,"y":712},{"x":92,"y":726},{"x":93,"y":825},{"x":94,"y":7},{"x":95,"y":846},{"x":96,"y":100},{"x":97,"y":509},{"x":98,"y":134},{"x":99,"y":434}]

这句是用于做位置偏移的data数据对象。

<div id="oscillogram></div>

在上面这个盒子里面画我们的坐标轴以及曲线

D3画出的原理就是svg,图形中是由点和线段构成。首先我们添加一个svg

let svg = d3.select('#oscillogram').append('svg').attr('width', width).attr('height', height).attr('stroke', '#fff')```

接下来我们需要设置横纵坐标的范围阈值等信息

let xScale = d3.scaleLinear().domain([0, 100]).range([0, 400]);
let yScale = d3.scaleLinear().domain([0, 900).range([900, 0]);

接下来我们分别分三个函数来画线,网格,坐标,以及数据点

		//xScale 和yScale即为上文中所取,svg为添加的svg对象。width和height为你想要添加进去的盒子容器的宽高
		this.drawLine(xScale, yScale, svg);
        this.drawCircle(xScale, yScale, svg);
        this.drawAxis(xScale, yScale, svg, height, width);
        this.drawGrid(yScale, svg);

drawAxis(xScale, yScale, svg, height, width)
    {
    //这里是设置坐标轴的样式,包括刻度的方向,文字颜色,等。
        let arr = [];
        for(let i = 0; i*5 < ToolPage.instance()._data.time; i++)
        {
            arr.push(i*5);
        }
        let arry = [];
        for(let i = 0; i * 50 < ToolPage.instance()._data.dataset[0].max; i++)
        {
            arry.push(i * 50);
        }
        let xAxis = svg.append('g')
            .attr('class', 'xAxis')
            .attr('transform', 'translate(' + ToolPage.instance()._data.padding.left + ', ' + (height - 10)+ ')')
            .call(d3.axisTop(xScale).ticks(arr.length).tickSizeInner(0).tickValues(arr));
            svg.select('.xAxis').select('path').attr('stroke','#fff');

        let yAxis = svg.append('g')
            .attr('class', 'yAxis')
            .attr('transform', 'translate(' + ToolPage.instance()._data.padding.left + ', ' + ToolPage.instance()._data.padding.top + ')')
            .style('font-size', '13')
            .call(d3.axisLeft(yScale).ticks(arry.length).tickValues(arry).tickSize(0).tickFormat(d3.format("d")) );
        svg.select('.yAxis').select('path').attr('stroke','#fff');
    }


drawLine(xScale, yScale, svg)
    {
    //画曲线,并设置对应的样式
        var linePath = d3.line().curve(d3.curveBasis).x(function (d)
        {
            return xScale(d.x);
        }).y(function (d)
        {
            return yScale(d.y);
        });
        //我这里,将两条曲线的数组存到了dataset数组第一个元素的gainVal对象种,这个对象也是一个数组对象
        svg.selectAll('path').data(this._data.dataset[0].gainVal).enter().append('path')
        .attr('transform', 'translate(' +this._data.padding.left + ', ' + this._data.padding.top + ')')
        .attr('d', function(d, i)
        {
            return linePath(d);
        })
        .attr('fill', 'none').attr('stroke', function (d, i)//加了这个函数循环,就可以给两条线做不同的样式了i=0则是第一条曲线,i=1就是第二条曲线,以此类推
        {
            let color;
            if(i === 0)
            {
                color = "#fff";
            }
            else
            {
                color = "yellowgreen";
            }
            return color
        }).attr('stroke-width', 1);
    }

drawCircle(xScale, yScale, svg)
    {
    //画数据点并设置对应的样式
        let circle = svg.selectAll('circle').data(ToolPage.instance()._data.dataset[0].gainVal).enter().append('circle')
        .attr('transform', 'translate(' + ToolPage.instance()._data.padding.left + ', ' + ToolPage.instance()._data.padding.top + ')')
        .attr('fill', 'black')
        .attr('cx', function (d)
        {
            return xScale(d.x);
        })
        .attr('cy', function (d)
        {
            return yScale(d.y);
        })
        .attr('r', 2)//设置曲线的宽度。
        .on('mouseover', function (d,i)//设置数据点的滑入滑出样式
        {
            console.log(d)
            d3.select(this).attr('fill', '#797979');
        })
        .on('mouseout', function (d,i)
        {
            d3.select(this).transition().duration(300).attr('fill', 'black');
        });
    }

drawGrid(yScale, svg)
    {
    //这里是画对应y轴刻度引出的横线
        let arry = [];
        for(let i = 0; i * 50 < ToolPage.instance()._data.dataset[0].max; i++)
        {
            arry.push(i * 50);
        }
        let yInner = d3.axisLeft(yScale).ticks(arry.length).tickValues(arry).tickSize(-document.querySelector('#oscillogram').clientWidth - 20).tickFormat(d =>  '');
        let yInnerBar = svg.append("g")
            .attr("class", "grid")
            .attr("transform", "translate(40," + ToolPage.instance()._data.padding.top + ")")
            .call(yInner);
            svg.select('.grid').select('path').attr('stroke','none');
            svg.select('.grid').selectAll('.tick').select('line').attr('stroke',function (d, i)
            {
                let color ;
                if(d === this._data.vData)//这里可以单独拿出一个刻度来设置不同的样式。我这里将和我数据对应的刻度写成了黄绿色
                {
                    color = "yellowgreen";
                }
                else
                {
                    color = "#ccc";
                }
                return color;
            }).attr('stroke-width', '0.6');
    }

最后添加一个移除节点的事件接口,方便刷新的时候随时调取更新
removeSVGDom()
    {
        let lineItems = document.querySelector('#oscillogram');
        let svgDom;
        svgDom = lineItems.querySelector('svg');
        if(svgDom !== null)
        {
            svgDom.remove();
        }
    }
核心代码如上,记录在CSDN主要为了便于自己记忆。如果有需要的朋友,欢迎参考。

http://www.niftyadmin.cn/n/1143575.html

相关文章

Vue项目中使用quill富文本编辑器

最近新起了一个项目,弃用之前的UE富文本编辑器,通过调研决定使用quill,一个很简单的小插件哈,以下是我的使用经验 1. 安装 npm install vue-quill-edito 2. 引用注册 //引用 import quill/dist/quill.core.css;import quill/dist/quill.snow.css;import quill/dist/quill.b…

js实现模糊搜索下的文字高亮显示

因为项目需求写了一段模糊搜索文字高亮显示的功能&#xff0c; 效果如下: 话不多说&#xff0c;直接甩代码&#xff1a; //this.searchValue 为搜索项 匹配搜索项与this.fileList[index].fullName是否匹配 然后 //返回匹配项数组searchMatchArr.涉及到了模糊搜索,故而做了大小…

电灯泡的题

TimeLimit:1000MS MemoryLimit:128MB 64-bit integer IO format:%lld Problem Description V_Dragon有n栈电灯泡&#xff0c;编号为1-n&#xff0c;每个灯泡都有一个开关。那么问题来了 所有灯泡初始时为不亮的 V_Dragon分别进行三次操作 每次操作他都选一个质数x&#x…

为什么死循环了

上述代码陷入死循环的原因&#xff1a; 内存空间氛围栈区&#xff0c;堆区&#xff0c;静态区&#xff1b; 其中栈区是存储局部变量&#xff1b; 原因&#xff1a; 1.栈区的默认使用&#xff1a; 先使用高地址处的空间&#xff1b; 再使用低地址处的空间 2.数组随着下边…

神奇的指针

具体内存布局如上 //两个指针相减代表两个指针之间的元素个数 //指针相减(地址1-地址2)/sizeof(类型) 这个你把他当成定律 &#xff0c;你要记牢。 //说白了还是指针类型加减整数跳跃的是一个类型 如 int *p;p1 意思就是 p跳跃一个整型 char *p; p1 意思就是 p跳…

指针的爱情

代码含义 char *a "asdsad"&#xff1b; 存入的是 字符串首元素地址 a是一个数组&#xff0c;数组中存放的类型的是char* 即指针数组 二级指针含义 pa是一个指针 *pa 指针指向 字符指针 char* *pa a 类比 int *p p是一个指针 *p 指针指向…

套娃的指针

c是一个数组&#xff0c; 存放内容是指针&#xff0c; 叫指针数组 cp是一个数组 存放内容是 指针的指针&#xff0c;叫二级指针数组 别废话&#xff0c;画个图就知道了 如上

大数运算之大数减法

蝈蝈的a-b&#xff08;middle&#xff09;TimeLimit:1000MS MemoryLimit:64MB64-bit integer IO format:%lld已解决 | 点击收藏Problem Description顾名思义&#xff0c;输入整数 a 和 b&#xff0c;输出 a - bInput输入一行两个整数 a 和 b&#xff08;1 ≤ lena&#xff0c;l…