@rfkit/renderer 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +2 -2
- package/index.d.ts.map +1 -1
- package/index.js +18 -4
- package/package.json +1 -1
- package/renderers/cartesian/Series.d.ts +33 -7
- package/renderers/cartesian/Series.d.ts.map +1 -1
- package/renderers/cartesian/SeriesCanvas.d.ts +13 -0
- package/renderers/cartesian/SeriesCanvas.d.ts.map +1 -0
- package/renderers/cartesian/index.d.ts +2 -1
- package/renderers/cartesian/index.d.ts.map +1 -1
- package/renderers/webgl/HeatmapWebGL.d.ts.map +1 -1
package/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { default as ColorInterpolator } from './color/ColorInterpolator';
|
|
2
2
|
export { color2intensity, hexToRGBA, rgbToHex } from './color/ColorUtils';
|
|
3
|
-
export type { IHeatmap } from './renderers/cartesian';
|
|
4
|
-
export { createHeatmap, Fluorescence, Gauge, Heatmap, HeatmapCanvas, Series } from './renderers/cartesian';
|
|
3
|
+
export type { IHeatmap, ISeries } from './renderers/cartesian';
|
|
4
|
+
export { createHeatmap, createSeries, Fluorescence, Gauge, Heatmap, HeatmapCanvas, Series, SeriesCanvas } from './renderers/cartesian';
|
|
5
5
|
export { Dial, Radar } from './renderers/circular';
|
|
6
6
|
export { IQ, IQEye } from './renderers/scatter';
|
|
7
7
|
export { HeatmapWebGL, SeriesWebGL } from './renderers/webgl';
|
package/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACzE,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC1E,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,KAAK,EACL,OAAO,EACP,aAAa,EACb,MAAM,EACN,YAAY,EACb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EACL,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,WAAW,EACX,KAAK,MAAM,EACX,eAAe,EACf,YAAY,EACZ,KAAK,YAAY,EACjB,KAAK,UAAU,EAChB,MAAM,SAAS,CAAC"}
|
package/index.js
CHANGED
|
@@ -7,7 +7,7 @@ void main() {
|
|
|
7
7
|
// 将 [-1, 1] 映射到 [0, 1]
|
|
8
8
|
v_texCoord = a_position * 0.5 + 0.5;
|
|
9
9
|
}
|
|
10
|
-
`;const FRAGMENT_SHADER=`#version 300 es
|
|
10
|
+
`;const INVALID_VALUE=-34028235e31;const FRAGMENT_SHADER=`#version 300 es
|
|
11
11
|
precision highp float;
|
|
12
12
|
|
|
13
13
|
in vec2 v_texCoord;
|
|
@@ -18,9 +18,23 @@ uniform sampler2D u_colorTexture;
|
|
|
18
18
|
uniform float u_rangeMin;
|
|
19
19
|
uniform float u_rangeMax;
|
|
20
20
|
|
|
21
|
+
// 特殊标记值,用于表示无效数据(NaN、空行等)
|
|
22
|
+
const float INVALID_VALUE = -3.4028235e+38;
|
|
23
|
+
|
|
21
24
|
void main() {
|
|
25
|
+
// Y 轴翻转:从底部向上绘制(与 Canvas 版本一致)
|
|
26
|
+
vec2 flippedCoord = vec2(v_texCoord.x, 1.0 - v_texCoord.y);
|
|
27
|
+
|
|
22
28
|
// 采样数据纹理获取原始值
|
|
23
|
-
float value = texture(u_dataTexture,
|
|
29
|
+
float value = texture(u_dataTexture, flippedCoord).r;
|
|
30
|
+
|
|
31
|
+
// 检查是否为无效值(特殊标记或 NaN)
|
|
32
|
+
// 注意:GLSL 中 NaN != NaN,所以 value != value 可以检测 NaN
|
|
33
|
+
if (value <= INVALID_VALUE || value != value) {
|
|
34
|
+
// 无效数据显示为透明
|
|
35
|
+
fragColor = vec4(0.0, 0.0, 0.0, 0.0);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
24
38
|
|
|
25
39
|
// 归一化到 [0, 1]
|
|
26
40
|
float normalized = (value - u_rangeMin) / (u_rangeMax - u_rangeMin);
|
|
@@ -29,7 +43,7 @@ void main() {
|
|
|
29
43
|
// 从颜色查找纹理获取颜色
|
|
30
44
|
fragColor = texture(u_colorTexture, vec2(normalized, 0.5));
|
|
31
45
|
}
|
|
32
|
-
`;class HeatmapWebGL extends WebGLEngine{init(props){super.init(props);const{gl}=this.state;if(!gl)return;const{colors=[],range}=props;const program=this.createProgram({vertex:VERTEX_SHADER,fragment:FRAGMENT_SHADER});const quadBuffer=this.createQuadBuffer();const dataTexture=this.createTexture();const colorTexture=this.createTexture();const[rangeMin,rangeMax]=range??[-20,100];const CI=colors.length>0?new ColorInterpolator(colors,rangeMin,rangeMax,.1):null;this.updateProps({data:[],colors,program,quadBuffer,dataTexture,colorTexture,dataWidth:0,dataHeight:0,CI});if(CI)this.updateColorTexture();this.resize()}updateColorTexture(){const{gl,colorTexture,CI,range}=this.state;if(!gl||!colorTexture||!CI)return;const[rangeMin,rangeMax]=range;const size=256;const colorData=new Uint8Array(4*size);for(let i=0;i<size;i++){const value=rangeMin+i/(size-1)*(rangeMax-rangeMin);const color=CI.getColor(value);colorData[4*i]=color.r;colorData[4*i+1]=color.g;colorData[4*i+2]=color.b;colorData[4*i+3]=color.a}gl.bindTexture(gl.TEXTURE_2D,colorTexture);gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,size,1,0,gl.RGBA,gl.UNSIGNED_BYTE,colorData)}updateDataTexture(){const{gl,dataTexture,data}=this.state;if(!gl||!dataTexture||0===data.length)return;const height=data.length;const width=data[0]?.length??0;if(0===width)return;const floatData=new Float32Array(width*height);for(let row=0;row<height;row++){const rowData=data[row];for(let col=0;col<width;col++)floatData[row*width+col]=rowData[col]??0}gl.bindTexture(gl.TEXTURE_2D,dataTexture);gl.texImage2D(gl.TEXTURE_2D,0,gl.R32F,width,height,0,gl.RED,gl.FLOAT,floatData);this.updateProps({dataWidth:width,dataHeight:height})}updateProps(e){super.updateProps(e);const{colors=this.state.colors,range=this.state.range}=e;if((e.colors||e.range)&&colors.length>0){const[rangeMin,rangeMax]=range;if(this.state.CI)this.state.CI.setColors(colors,rangeMin,rangeMax,.1);else this.state.CI=new ColorInterpolator(colors,rangeMin,rangeMax,.1);this.updateColorTexture()}}setRange(range){if(!range)return;this.updateProps({range});this.draw()}clear(){this.clearRect();this.updateProps({data:[]})}render(data){if(data?.length>=0){this.state.data=data;this.updateDataTexture();this.draw()}}draw(){const{gl,program,quadBuffer,dataTexture,colorTexture,data,range}=this.state;if(!gl||!program||!quadBuffer||!dataTexture||!colorTexture)return;if(0===data.length)return;const[rangeMin,rangeMax]=range;gl.clearColor(0,0,0,0);gl.clear(gl.COLOR_BUFFER_BIT);gl.useProgram(program);gl.bindBuffer(gl.ARRAY_BUFFER,quadBuffer);const positionLoc=gl.getAttribLocation(program,"a_position");gl.enableVertexAttribArray(positionLoc);gl.vertexAttribPointer(positionLoc,2,gl.FLOAT,false,0,0);gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D,dataTexture);gl.uniform1i(gl.getUniformLocation(program,"u_dataTexture"),0);gl.activeTexture(gl.TEXTURE1);gl.bindTexture(gl.TEXTURE_2D,colorTexture);gl.uniform1i(gl.getUniformLocation(program,"u_colorTexture"),1);gl.uniform1f(gl.getUniformLocation(program,"u_rangeMin"),rangeMin);gl.uniform1f(gl.getUniformLocation(program,"u_rangeMax"),rangeMax);gl.drawArrays(gl.TRIANGLES,0,6)}resize(){super.resize()}dispose(){const{gl,program,quadBuffer,dataTexture,colorTexture}=this.state;if(gl){if(program)gl.deleteProgram(program);if(quadBuffer)gl.deleteBuffer(quadBuffer);if(dataTexture)gl.deleteTexture(dataTexture);if(colorTexture)gl.deleteTexture(colorTexture)}super.dispose()}}class HeatmapCanvas extends Engine{init(props){super.init(props);const{colors}=props;this.updateProps({colors,data:[]});this.resize()}updateProps(e){super.updateProps(e);const{range=this.state.range,colors=this.state.colors}=e;if(range&&colors){const[rangeMin,rangeMax]=range;if(isNumberAlias(rangeMin)&&isNumberAlias(rangeMax)&&rangeMin<rangeMax){if(this.state.CI)this.state.CI.setColors(colors,rangeMin,rangeMax,.1);else this.updateProps({CI:new ColorInterpolator(colors,rangeMin,rangeMax,.1)})}}}clearImageData(){const{ctx,canvas:{height,width}}=this.state;if(height&&width)this.updateProps({imageData:ctx.createImageData(width,height)})}clearRect(){super.clearRect();this.clearImageData()}clear(){this.clearRect();this.updateProps({data:[]})}resize(){super.resize();this.clearImageData()}setRange(range){if(!range)return;this.updateProps({range});this.draw()}render(data){if(data?.length>=0){this.state.data=data;this.draw()}}draw(){const{imageData,data,canvas,ctx,CI}=this.state;if(0===data.length)return;fillImageData(canvas.width,canvas.height,data,imageData.data,value=>CI.getColor(value));ctx.putImageData(imageData,0,0)}}function createHeatmap(props){const{renderer=enums_RendererType.Canvas}=props;if(renderer===enums_RendererType.WebGL)return new HeatmapWebGL(props);return new HeatmapCanvas(props)}const Heatmap_Heatmap=function(props){return createHeatmap(props)};const cartesian_Heatmap=Heatmap_Heatmap;const ENABLE_AREA_GRADIENT=false;class Series extends Engine{init(props){super.init(props);const{series,barValue2Color,disabledClearRect,colors}=props;this.updateProps({interval:0,series:{},barValue2Color,disabledClearRect,colors});this.setRange(this.state.range);if(Array.isArray(series))series.forEach(e=>{this.setSeries(e)})}updateProps(e){super.updateProps(e);const{colors=this.state.colors}=e;if(this.state.barValue2Color&&!this.state.CI&&colors)this.updateProps({CI:new ColorInterpolator(colors,0,100,.1)})}clear(){super.clearRect();const{series}=this.state;const seriesArray=Object.entries(series);seriesArray.forEach(([name,i])=>{this.setSeries({...i,name,data:void 0})})}setRange(range){this.updateProps({range:[range[0],range[1],range[1]-range[0]]});this.draw()}setIntervel(interval){if(!interval)return;this.updateProps({interval})}setSeries(e){if(e?.name){const{name}=e;const{series}=this.state;series[name]={thickness:1,display:true,color:"#000000",type:enums_GraphicType.Line,data:void 0,path:void 0,orientation:enums_OrientationType.Vertical,...series[name],...e};this.draw()}}render(e){e&&this.setSeries(e);this.draw()}draw(){const{series,ctx,disabledClearRect}=this.state;if(!disabledClearRect)this.clearRect();const seriesArray=Object.values(series);const{range,canvas}=this.state;const min=range[0];const max=range[1];const{width,height}=canvas;const rangeY=max-min;ctx.save();ctx.translate(.5,.5);for(let s=0;s<seriesArray.length;s+=1){const seriesItem=seriesArray[s];const{display,type,data,orientation}=seriesItem;const thickness=seriesItem.thickness??DEFAULTS.THICKNESS;const color=seriesItem.color??DEFAULTS.COLOR;if(!data||!display)continue;const len=data.length;const per=width/len;switch(type){case enums_GraphicType.Line:case enums_GraphicType.Stepline:ctx.lineWidth=thickness;ctx.strokeStyle=color;break;case enums_GraphicType.Circle:case enums_GraphicType.Rect:case enums_GraphicType.Bar:case enums_GraphicType.Area:ctx.fillStyle=color;break}if(type===enums_GraphicType.Line){let points=[];for(let i=0;i<len;i+=1){const value=data[i];if(void 0===value||Number.isNaN(value)){if(points.length>0){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let j=1;j<points.length;j++)ctx.lineTo(points[j][0],points[j][1]);ctx.lineWidth=thickness;ctx.strokeStyle=color;ctx.stroke();points=[]}}else{const x=Math.round((i+.5)*per);const y=Math.round((value-min)/rangeY*height);points.push([x,y])}}if(points.length>0){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let j=1;j<points.length;j++)ctx.lineTo(points[j][0],points[j][1]);ctx.lineWidth=thickness;ctx.strokeStyle=color;ctx.stroke()}}if(type===enums_GraphicType.Stepline){let points=[];for(let i=0;i<len;i+=1){const value=data[i];if(void 0===value||Number.isNaN(value)){if(points.length>0){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let j=1;j<points.length;j++){const[_,py]=points[j-1];const[cx,cy]=points[j];ctx.lineTo(cx,py);ctx.lineTo(cx,cy)}const[lx,ly]=points[points.length-1];const endX=Math.round(lx+per);ctx.lineTo(endX,ly);ctx.lineWidth=thickness;ctx.strokeStyle=color;ctx.stroke();points=[]}}else{const x=Math.round(i*per);const y=Math.round((value-min)/rangeY*height);points.push([x,y])}}if(points.length>0){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let j=1;j<points.length;j++){const[_,py]=points[j-1];const[cx,cy]=points[j];ctx.lineTo(cx,py);ctx.lineTo(cx,cy)}const[lx,ly]=points[points.length-1];const endX=Math.round(lx+per);ctx.lineTo(endX,ly);ctx.lineWidth=thickness;ctx.strokeStyle=color;ctx.stroke()}}if(type===enums_GraphicType.Circle){const radius=+thickness/2;const endAngle=2*Math.PI;for(let i=0;i<len;i+=1){const x=Math.round((i+.5)*per);const y=Math.round((data[i]-min)/rangeY*height);ctx.beginPath();ctx.arc(x,y,radius,0,endAngle);ctx.fillStyle=color;ctx.fill()}}if(type===enums_GraphicType.Rect){const side=+thickness;for(let i=0;i<len;i+=1){const x=Math.round((i+.5)*per);const y=Math.round((data[i]-min)/rangeY*height);ctx.beginPath();ctx.rect(x,y,side,side);ctx.fillStyle=color;ctx.fill()}}if(type===enums_GraphicType.Area){let points=[];const{r,g,b}=hexToRGBA(color??"#000000");const drawArea=pointsToDraw=>{if(0===pointsToDraw.length)return;const[firstX,firstY]=pointsToDraw[0];const[lastX,lastY]=pointsToDraw[pointsToDraw.length-1];const endX=Math.round(lastX+per);ctx.beginPath();ctx.moveTo(firstX,0);ctx.lineTo(firstX,firstY);for(let j=1;j<pointsToDraw.length;j++){const[_,prevY]=pointsToDraw[j-1];const[currX,currY]=pointsToDraw[j];ctx.lineTo(currX,prevY);ctx.lineTo(currX,currY)}ctx.lineTo(endX,lastY);ctx.lineTo(endX,0);ctx.closePath();if(ENABLE_AREA_GRADIENT){const gradient=ctx.createLinearGradient(0,0,0,height);gradient.addColorStop(0,`rgba(${r}, ${g}, ${b}, 0)`);gradient.addColorStop(1,`rgba(${r}, ${g}, ${b}, 0.5)`);ctx.fillStyle=gradient}else ctx.fillStyle=`rgba(${r}, ${g}, ${b}, 1)`;ctx.fill()};for(let i=0;i<len;i+=1){const value=data[i];if(void 0===value||Number.isNaN(value)){drawArea(points);points=[]}else points.push([Math.round(i*per),Math.round((value-min)/rangeY*height)])}drawArea(points)}if(type===enums_GraphicType.Bar){if(orientation===enums_OrientationType.Horizontal){const h=height/len;const hh=Math.round(h);for(let i=0;i<len;i+=1){const y=Math.round(height-(i+1)*h);const w=Math.round((data[i]-min)/rangeY*width);const x=width-w;ctx.beginPath();ctx.rect(x,y,w,hh);ctx.fillStyle=color;ctx.fill()}}else for(let i=0;i<len;i+=1){const startX=Math.floor(i*width/len);const endX=Math.floor((i+1)*width/len);const w=endX-startX;const h=Math.round((data[i]-min)/rangeY*height);ctx.beginPath();ctx.rect(startX,0,w,h);ctx.fillStyle=this.state.barValue2Color?this.state.CI?.getColor(data[i]).hax??color:color;ctx.fill()}}}ctx.restore()}}function getCoordinates(radius,padding,angle){const x=radius+(radius-padding)*Math.cos(angle);const y=radius+(radius-padding)*Math.sin(angle);return[x,y]}class CircularBase extends Engine{getSpecialTickConfig(_angle){}getAngleOffset(){return 0}init(props){super.init(props);this.state.canvas.style.transform="scaleY(1)";const fillStyle=props.fillStyle??DEFAULTS.FILL_STYLE;const fillStylePrimary=props.fillStylePrimary??DEFAULTS.FILL_STYLE_PRIMARY;const fillStyleTransparentBase=props.fillStyleTransparentBase??DEFAULTS.FILL_STYLE_TRANSPARENT_BASE;const markedNum=12;const baseWidth=6;this.updateProps({fillStyle,fillStylePrimary,fillStyleTransparentBase,baseWidth,padding:10*baseWidth,ticksStep:6,ticksRenderLength:5,markedAngles:Array.from({length:markedNum},(_,i)=>360/markedNum*i),color2intensity:color2intensity(fillStylePrimary),data:{series:[],range:[0,0],yawAngle:0,isNorthFacing:true}})}clear(){this.clearRect()}resize(){super.resize();if(this.state.markedAngles)this.drawBackground();if(this.state.data)this.drawTicks()}render(data){const isYawAngleChange=void 0!==data.yawAngle&&data.yawAngle!==this.state.data?.yawAngle;this.state.data={...this.state.data,...data};if(isYawAngleChange)this.drawTicks();this.draw()}drawTicks(){const{canvas,baseWidth,fillStyle,fillStylePrimary,ticksStep,ticksRenderLength,markedAngles,data}=this.state;const{yawAngle=0,isNorthFacing=true}=data;const ticksCanvas=document.createElement("canvas");ticksCanvas.width=canvas.width;ticksCanvas.height=canvas.height;const ticksCtx=ticksCanvas.getContext("2d");if(!ticksCtx)return;const radius=canvas.width/2;const northYawgle=isNorthFacing?0:-yawAngle;for(let i=0;i<360;i+=ticksStep){const angle=(i+northYawgle)*Math.PI/180;const isMarked=markedAngles.includes(i);const length=ticksRenderLength*(isMarked?1.2:1);const[x,y]=getCoordinates(radius,3.5*baseWidth+length+(isMarked?3:0),angle);const[xOuter,yOuter]=getCoordinates(radius,3.5*baseWidth,angle);ticksCtx.beginPath();ticksCtx.moveTo(x,y);ticksCtx.lineTo(xOuter,yOuter);ticksCtx.strokeStyle=fillStyle;ticksCtx.lineWidth=isMarked?2:.5;ticksCtx.stroke()}ticksCtx.font=`${2*baseWidth}px Arial`;ticksCtx.textAlign="center";ticksCtx.textBaseline="middle";markedAngles.forEach(angle=>{const radian=(angle+northYawgle-90)*Math.PI/180;const[x,y]=getCoordinates(radius,8*baseWidth,radian);const specialConfig=this.getSpecialTickConfig(angle);if(specialConfig){ticksCtx.fillStyle=specialConfig.color;ticksCtx.fillText(specialConfig.alias,x,y)}else{ticksCtx.fillStyle=fillStyle;ticksCtx.fillText(angle.toString(),x,y)}});const arrowWidth=canvas.width/18;ticksCtx.translate(canvas.width/2,canvas.height/2);ticksCtx.scale(1,-1);ticksCtx.rotate((isNorthFacing?-yawAngle:0)*Math.PI/180);ticksCtx.lineJoin="round";ticksCtx.lineCap="round";ticksCtx.strokeStyle=fillStylePrimary;ticksCtx.fillStyle=fillStylePrimary;ticksCtx.lineWidth=arrowWidth/6;ticksCtx.beginPath();ticksCtx.moveTo(0,arrowWidth/2);ticksCtx.lineTo(arrowWidth/2,-arrowWidth/2);ticksCtx.lineTo(0,arrowWidth/2-1/((1+Math.sqrt(5))/2)*arrowWidth);ticksCtx.lineTo(-arrowWidth/2,-arrowWidth/2);ticksCtx.lineTo(0,arrowWidth/2);ticksCtx.fill();ticksCtx.stroke();this.state.ticksCanvas=ticksCanvas}drawBackground(){const{canvas,baseWidth,padding,fillStyleTransparentBase}=this.state;const BGCanvas=document.createElement("canvas");BGCanvas.width=canvas.width;BGCanvas.height=canvas.height;const BGCtx=BGCanvas.getContext("2d");if(!BGCtx)return;const radius=canvas.width/2;BGCtx.beginPath();BGCtx.arc(radius,radius,radius-2*baseWidth,0,2*Math.PI);BGCtx.strokeStyle=fillStyleTransparentBase;BGCtx.lineWidth=baseWidth;BGCtx.stroke();new Array(5).fill(1).forEach((_,i)=>{BGCtx.beginPath();BGCtx.arc(radius,radius,(radius-padding)*(i+1)/5,0,2*Math.PI);BGCtx.strokeStyle=fillStyleTransparentBase;BGCtx.lineWidth=baseWidth/4;BGCtx.stroke()});this.state.BGCanvas=BGCanvas}draw(){const{data,canvas,ctx,baseWidth,padding,BGCanvas,ticksCanvas,color2intensity:c2i,fillStyleTransparentBase}=this.state;const{series,range,isNorthFacing=true,yawAngle=0}=data;if(!series)return;this.clearRect();const radius=canvas.width/2;const northYawgle=isNorthFacing?0:-yawAngle;const angleOffset=this.getAngleOffset();if(BGCanvas)ctx.drawImage(BGCanvas,0,0);if(range){const sliceAngle=360/range.length;range.forEach((value,index)=>{const startAngle=(index*sliceAngle+northYawgle+angleOffset)*Math.PI/180;const endAngle=((index+1)*sliceAngle+northYawgle+angleOffset)*Math.PI/180;ctx.beginPath();ctx.moveTo(radius,radius);ctx.arc(radius,radius,radius-padding,startAngle,endAngle);ctx.closePath();ctx.fillStyle=c2i[value];ctx.fill()})}series.forEach(({value,color,lineWidth=baseWidth,radio=1})=>{if(null==value)return;const pointerAngle=(value+northYawgle)*Math.PI/180-Math.PI/2;const[startX,startY]=getCoordinates(radius,radius,pointerAngle);const[endX,endY]=getCoordinates(radius,padding+(1-radio)*(radius-padding)+lineWidth/2,pointerAngle);if(1!==radio){ctx.beginPath();ctx.moveTo(...getCoordinates(radius,padding+lineWidth/2,pointerAngle));ctx.lineTo(endX,endY);ctx.strokeStyle=fillStyleTransparentBase;ctx.stroke()}ctx.beginPath();ctx.moveTo(endX,endY);ctx.lineTo(startX,startY);ctx.strokeStyle=color;ctx.lineWidth=lineWidth;ctx.lineJoin="round";ctx.lineCap="round";ctx.stroke()});if(ticksCanvas)ctx.drawImage(ticksCanvas,0,0)}}const SPECIAL_TICK_CONFIG={0:{color:"#ff4d4f",alias:"北"},180:{color:"#1890ff",alias:"南"}};class Dial extends CircularBase{getSpecialTickConfig(angle){return SPECIAL_TICK_CONFIG[angle]}getAngleOffset(){return -90}}class Radar extends CircularBase{getSpecialTickConfig(_angle){}getAngleOffset(){return 0}}class IQ extends Engine{init(props){super.init(props);this.updateProps({lineColor:props.lineColor??DEFAULTS.LINE_COLOR,pointColor:props.pointColor??DEFAULTS.POINT_COLOR})}clear(){this.clearRect();this.updateProps({data:{IData:[],QData:[]}})}render(data){if(data.IData&&data.QData){this.state.data=data;this.draw()}}draw(){const{data,canvas,pointColor,lineColor,ctx}=this.state;if(!data)return;const{IData,QData}=data;if(0===IData.length||0===QData.length)return;const{width,height}=ctx.canvas;ctx.clearRect(0,0,canvas.width,canvas.height);const[minX,maxX]=getMinMax(IData);const[minY,maxY]=getMinMax([minX,maxX,...QData]);const xScale=width/(maxX-minX);const yScale=height/(maxY-minY);const pointRadius=2;const points=IData.map((xVal,i)=>{const x=(xVal-minX)*xScale;const y=(QData[i]-minY)*yScale;return{x,y}});ctx.beginPath();points.forEach((point,i)=>{ctx[0===i?"moveTo":"lineTo"](point.x,point.y)});ctx.strokeStyle=lineColor;ctx.lineWidth=1;ctx.stroke();points.forEach(point=>{ctx.beginPath();ctx.arc(point.x,point.y,pointRadius,0,2*Math.PI);ctx.fillStyle=pointColor;ctx.fill()})}}const EYE_CONFIG={Y_RANGE:{MIN:-1,MAX:1},SEGMENT_SIZE:5};class IQEye extends Engine{init(props){super.init(props);this.updateProps({lineColor:props.lineColor??DEFAULTS.LINE_COLOR,pointColor:props.pointColor??DEFAULTS.POINT_COLOR})}clear(){this.clearRect();this.updateProps({data:{IData:[],QData:[]}})}render(data){if(data.IData&&data.QData){this.state.data=data;this.draw()}}draw(){if(!this.state.data)return;const{data:{IData,QData},ctx,canvas}=this.state;if(0===IData.length||0===QData.length)return;this.clearRect();const min=EYE_CONFIG.Y_RANGE.MIN;const rangeY=EYE_CONFIG.Y_RANGE.MAX-EYE_CONFIG.Y_RANGE.MIN;const{width,height}=canvas;const offscreenCanvas=document.createElement("canvas");offscreenCanvas.width=width;offscreenCanvas.height=height;const offCtx=offscreenCanvas.getContext("2d",{willReadFrequently:true});if(!offCtx)return;this.drawAllSegments(IData,QData,min,rangeY,width,height,offCtx);const imageData=offCtx.getImageData(0,0,width,height);const data=imageData.data;this.applyColorGradient(data);ctx.putImageData(imageData,0,0)}drawAllSegments(iData,qData,min,rangeY,width,height,ctx){ctx.clearRect(0,0,width,height);const accumulator=new Uint8Array(width*height);this.drawSegmentedData(iData,min,rangeY,width,height,accumulator);this.drawSegmentedData(qData,min,rangeY,width,height,accumulator);const imageData=ctx.getImageData(0,0,width,height);const data=imageData.data;for(let i=0;i<accumulator.length;i++)if(accumulator[i]>0){const index=4*i;data[index]=255;data[index+1]=255;data[index+2]=255;data[index+3]=Math.min(50*accumulator[i],255)}ctx.putImageData(imageData,0,0)}applyColorGradient(data){const{lineColor,pointColor}=this.state;const startColor=parseColor(lineColor);const endColor=parseColor(pointColor);for(let i=0;i<data.length;i+=4)if(data[i+3]>0){const intensity=data[i+3]/255;data[i]=Math.round(startColor.r+(endColor.r-startColor.r)*intensity);data[i+1]=Math.round(startColor.g+(endColor.g-startColor.g)*intensity);data[i+2]=Math.round(startColor.b+(endColor.b-startColor.b)*intensity)}}drawSegmentedData(data,min,rangeY,width,height,accumulator){const segmentSize=EYE_CONFIG.SEGMENT_SIZE;const segmentCount=Math.ceil(data.length/segmentSize);const pointSpacing=width/(segmentSize-1);for(let segment=0;segment<segmentCount;segment++){const points=[];for(let i=0;i<segmentSize;i++){const dataIndex=segment*segmentSize+i;if(dataIndex>=data.length)continue;const value=data[dataIndex];if(void 0!==value){const x=Math.round(i*pointSpacing);const y=Math.round((value-min)/rangeY*height);points.push({x,y})}}if(points.length>1)for(let i=0;i<points.length-1;i++)this.drawLine(points[i].x,points[i].y,points[i+1].x,points[i+1].y,width,height,accumulator)}}drawLine(x0,y0,x1,y1,width,height,accumulator){const dx=Math.abs(x1-x0);const dy=Math.abs(y1-y0);const sx=x0<x1?1:-1;const sy=y0<y1?1:-1;let x=x0;let y=y0;let err=dx-dy;while(true){if(x>=0&&x<width&&y>=0&&y<height){const index=y*width+x;if(accumulator[index]<255)accumulator[index]++}if(x===x1&&y===y1)break;const e2=2*err;if(e2>-dy){err-=dy;x+=sx}if(e2<dx){err+=dx;y+=sy}}}}const MAX_VERTICES=36e4;const SeriesWebGL_VERTEX_SHADER=`#version 300 es
|
|
46
|
+
`;class HeatmapWebGL extends WebGLEngine{init(props){super.init(props);const{gl}=this.state;if(!gl)return;const{colors=[],range}=props;const program=this.createProgram({vertex:VERTEX_SHADER,fragment:FRAGMENT_SHADER});const quadBuffer=this.createQuadBuffer();const dataTexture=this.createTexture();const colorTexture=this.createTexture();const[rangeMin,rangeMax]=range??[-20,100];const CI=colors.length>0?new ColorInterpolator(colors,rangeMin,rangeMax,.1):null;this.updateProps({data:[],colors,program,quadBuffer,dataTexture,colorTexture,dataWidth:0,dataHeight:0,CI});if(CI)this.updateColorTexture();this.resize()}updateColorTexture(){const{gl,colorTexture,CI,range}=this.state;if(!gl||!colorTexture||!CI)return;const[rangeMin,rangeMax]=range;const size=256;const colorData=new Uint8Array(4*size);for(let i=0;i<size;i++){const value=rangeMin+i/(size-1)*(rangeMax-rangeMin);const color=CI.getColor(value);colorData[4*i]=color.r;colorData[4*i+1]=color.g;colorData[4*i+2]=color.b;colorData[4*i+3]=color.a}gl.bindTexture(gl.TEXTURE_2D,colorTexture);gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,size,1,0,gl.RGBA,gl.UNSIGNED_BYTE,colorData)}updateDataTexture(){const{gl,dataTexture,data}=this.state;if(!gl||!dataTexture||0===data.length)return;const height=data.length;let width=0;for(let row=0;row<height;row++){const rowLen=data[row]?.length??0;if(rowLen>width)width=rowLen}if(0===width)return;const floatData=new Float32Array(width*height);for(let row=0;row<height;row++){const rowData=data[row];const rowLen=rowData?.length??0;for(let col=0;col<width;col++)if(0===rowLen||col>=rowLen)floatData[row*width+col]=INVALID_VALUE;else{const value=rowData[col];if(void 0===value||Number.isNaN(value))floatData[row*width+col]=INVALID_VALUE;else floatData[row*width+col]=value}}gl.bindTexture(gl.TEXTURE_2D,dataTexture);gl.texImage2D(gl.TEXTURE_2D,0,gl.R32F,width,height,0,gl.RED,gl.FLOAT,floatData);this.updateProps({dataWidth:width,dataHeight:height})}updateProps(e){super.updateProps(e);const{colors=this.state.colors,range=this.state.range}=e;if((e.colors||e.range)&&colors.length>0){const[rangeMin,rangeMax]=range;if(this.state.CI)this.state.CI.setColors(colors,rangeMin,rangeMax,.1);else this.state.CI=new ColorInterpolator(colors,rangeMin,rangeMax,.1);this.updateColorTexture()}}setRange(range){if(!range)return;this.updateProps({range});this.draw()}clear(){this.clearRect();this.updateProps({data:[]})}render(data){if(data?.length>=0){this.state.data=data;this.updateDataTexture();this.draw()}}draw(){const{gl,program,quadBuffer,dataTexture,colorTexture,data,range}=this.state;if(!gl||!program||!quadBuffer||!dataTexture||!colorTexture)return;if(0===data.length)return;const[rangeMin,rangeMax]=range;gl.clearColor(0,0,0,0);gl.clear(gl.COLOR_BUFFER_BIT);gl.useProgram(program);gl.bindBuffer(gl.ARRAY_BUFFER,quadBuffer);const positionLoc=gl.getAttribLocation(program,"a_position");gl.enableVertexAttribArray(positionLoc);gl.vertexAttribPointer(positionLoc,2,gl.FLOAT,false,0,0);gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D,dataTexture);gl.uniform1i(gl.getUniformLocation(program,"u_dataTexture"),0);gl.activeTexture(gl.TEXTURE1);gl.bindTexture(gl.TEXTURE_2D,colorTexture);gl.uniform1i(gl.getUniformLocation(program,"u_colorTexture"),1);gl.uniform1f(gl.getUniformLocation(program,"u_rangeMin"),rangeMin);gl.uniform1f(gl.getUniformLocation(program,"u_rangeMax"),rangeMax);gl.drawArrays(gl.TRIANGLES,0,6)}resize(){super.resize()}dispose(){const{gl,program,quadBuffer,dataTexture,colorTexture}=this.state;if(gl){if(program)gl.deleteProgram(program);if(quadBuffer)gl.deleteBuffer(quadBuffer);if(dataTexture)gl.deleteTexture(dataTexture);if(colorTexture)gl.deleteTexture(colorTexture)}super.dispose()}}class HeatmapCanvas extends Engine{init(props){super.init(props);const{colors}=props;this.updateProps({colors,data:[]});this.resize()}updateProps(e){super.updateProps(e);const{range=this.state.range,colors=this.state.colors}=e;if(range&&colors){const[rangeMin,rangeMax]=range;if(isNumberAlias(rangeMin)&&isNumberAlias(rangeMax)&&rangeMin<rangeMax){if(this.state.CI)this.state.CI.setColors(colors,rangeMin,rangeMax,.1);else this.updateProps({CI:new ColorInterpolator(colors,rangeMin,rangeMax,.1)})}}}clearImageData(){const{ctx,canvas:{height,width}}=this.state;if(height&&width)this.updateProps({imageData:ctx.createImageData(width,height)})}clearRect(){super.clearRect();this.clearImageData()}clear(){this.clearRect();this.updateProps({data:[]})}resize(){super.resize();this.clearImageData()}setRange(range){if(!range)return;this.updateProps({range});this.draw()}render(data){if(data?.length>=0){this.state.data=data;this.draw()}}draw(){const{imageData,data,canvas,ctx,CI}=this.state;if(0===data.length)return;fillImageData(canvas.width,canvas.height,data,imageData.data,value=>CI.getColor(value));ctx.putImageData(imageData,0,0)}}function createHeatmap(props){const{renderer=enums_RendererType.Canvas}=props;if(renderer===enums_RendererType.WebGL)return new HeatmapWebGL(props);return new HeatmapCanvas(props)}const Heatmap_Heatmap=function(props){return createHeatmap(props)};const cartesian_Heatmap=Heatmap_Heatmap;const MAX_VERTICES=36e4;const SeriesWebGL_VERTEX_SHADER=`#version 300 es
|
|
33
47
|
in vec2 a_position;
|
|
34
48
|
uniform vec2 u_resolution;
|
|
35
49
|
uniform float u_rangeMin;
|
|
@@ -103,4 +117,4 @@ out vec4 fragColor;
|
|
|
103
117
|
void main() {
|
|
104
118
|
fragColor = u_color;
|
|
105
119
|
}
|
|
106
|
-
`;class SeriesWebGL extends WebGLEngine{fillProgramWithColor=null;pointCircleProgram=null;pointRectProgram=null;lineUniforms=null;lineAttribs=null;fillUniforms=null;fillAttribs=null;fillColorUniforms=null;fillColorAttribs=null;pointCircleUniforms=null;pointCircleAttribs=null;pointRectUniforms=null;pointRectAttribs=null;vertexDataBuffer=new Float32Array(MAX_VERTICES);vertexColorBuffer=new Float32Array(MAX_VERTICES);init(props){super.init(props);const{gl}=this.state;if(!gl)return;const{series,barValue2Color,disabledClearRect,colors=[]}=props;const lineProgram=this.createProgram({vertex:SeriesWebGL_VERTEX_SHADER,fragment:SeriesWebGL_FRAGMENT_SHADER});const fillProgram=this.createProgram({vertex:SeriesWebGL_VERTEX_SHADER,fragment:SeriesWebGL_FRAGMENT_SHADER});this.fillProgramWithColor=this.createProgram({vertex:VERTEX_SHADER_WITH_COLOR,fragment:FRAGMENT_SHADER_WITH_COLOR});const pointProgram=this.createProgram({vertex:POINT_VERTEX_SHADER,fragment:POINT_CIRCLE_FRAGMENT_SHADER});this.pointCircleProgram=pointProgram;this.pointRectProgram=this.createProgram({vertex:POINT_VERTEX_SHADER,fragment:POINT_RECT_FRAGMENT_SHADER});this.cacheLocations(gl,lineProgram,fillProgram);const vertexBuffer=gl.createBuffer();const CI=barValue2Color&&colors.length>0?new ColorInterpolator(colors,0,100,.1):null;const colorTexture=this.createTexture();this.updateProps({series:{},colors,interval:props.interval??0,barValue2Color,disabledClearRect,lineProgram,fillProgram,pointProgram,vertexBuffer,colorTexture,CI});if(Array.isArray(series))series.forEach(e=>{this.setSeries(e)});gl.enable(gl.BLEND);gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA)}cacheLocations(gl,lineProgram,fillProgram){if(lineProgram){this.lineUniforms={resolution:gl.getUniformLocation(lineProgram,"u_resolution"),rangeMin:gl.getUniformLocation(lineProgram,"u_rangeMin"),rangeMax:gl.getUniformLocation(lineProgram,"u_rangeMax"),color:gl.getUniformLocation(lineProgram,"u_color")};this.lineAttribs={position:gl.getAttribLocation(lineProgram,"a_position")}}if(fillProgram){this.fillUniforms={resolution:gl.getUniformLocation(fillProgram,"u_resolution"),rangeMin:gl.getUniformLocation(fillProgram,"u_rangeMin"),rangeMax:gl.getUniformLocation(fillProgram,"u_rangeMax"),color:gl.getUniformLocation(fillProgram,"u_color")};this.fillAttribs={position:gl.getAttribLocation(fillProgram,"a_position")}}if(this.fillProgramWithColor){this.fillColorUniforms={resolution:gl.getUniformLocation(this.fillProgramWithColor,"u_resolution"),rangeMin:gl.getUniformLocation(this.fillProgramWithColor,"u_rangeMin"),rangeMax:gl.getUniformLocation(this.fillProgramWithColor,"u_rangeMax"),color:null};this.fillColorAttribs={position:gl.getAttribLocation(this.fillProgramWithColor,"a_position"),color:gl.getAttribLocation(this.fillProgramWithColor,"a_color")}}if(this.pointCircleProgram){this.pointCircleUniforms={resolution:gl.getUniformLocation(this.pointCircleProgram,"u_resolution"),rangeMin:gl.getUniformLocation(this.pointCircleProgram,"u_rangeMin"),rangeMax:gl.getUniformLocation(this.pointCircleProgram,"u_rangeMax"),color:gl.getUniformLocation(this.pointCircleProgram,"u_color"),pointSize:gl.getUniformLocation(this.pointCircleProgram,"u_pointSize")};this.pointCircleAttribs={position:gl.getAttribLocation(this.pointCircleProgram,"a_position")}}if(this.pointRectProgram){this.pointRectUniforms={resolution:gl.getUniformLocation(this.pointRectProgram,"u_resolution"),rangeMin:gl.getUniformLocation(this.pointRectProgram,"u_rangeMin"),rangeMax:gl.getUniformLocation(this.pointRectProgram,"u_rangeMax"),color:gl.getUniformLocation(this.pointRectProgram,"u_color"),pointSize:gl.getUniformLocation(this.pointRectProgram,"u_pointSize")};this.pointRectAttribs={position:gl.getAttribLocation(this.pointRectProgram,"a_position")}}}updateProps(e){super.updateProps(e);const{colors=this.state.colors}=e;if(this.state.barValue2Color&&!this.state.CI&&colors?.length>0)this.state.CI=new ColorInterpolator(colors,0,100,.1)}clear(){this.clearRect();const{series}=this.state;const seriesArray=Object.entries(series);seriesArray.forEach(([name,i])=>{this.setSeries({...i,name,data:void 0})})}setRange(range){this.updateProps({range:[range[0],range[1],range[1]-range[0]]});this.draw()}setIntervel(interval){if(!interval)return;this.updateProps({interval})}setSeries(e){if(e?.name){const{name}=e;const{series}=this.state;series[name]={thickness:1,display:true,color:"#000000",type:enums_GraphicType.Line,data:void 0,orientation:enums_OrientationType.Vertical,...series[name],...e};this.draw()}}render(e){e&&this.setSeries(e);this.draw()}draw(){const{gl,series,disabledClearRect,range,canvas}=this.state;if(!gl)return;if(!disabledClearRect)this.clearRect();const seriesArray=Object.values(series);const min=range[0];const max=range[1];const{width,height}=canvas;for(const seriesItem of seriesArray){const{display,type,data,orientation}=seriesItem;const thickness=seriesItem.thickness??DEFAULTS.THICKNESS;const color=seriesItem.color??DEFAULTS.COLOR;if(!!data&&!!display)switch(type){case enums_GraphicType.Line:this.drawLine(data,color,thickness,width,height,min,max);break;case enums_GraphicType.Stepline:this.drawStepline(data,color,thickness,width,height,min,max);break;case enums_GraphicType.Bar:this.drawBar(data,color,width,height,min,max,orientation??enums_OrientationType.Vertical);break;case enums_GraphicType.Area:this.drawArea(data,color,width,height,min,max);break;case enums_GraphicType.Circle:this.drawPoints(data,color,thickness,width,height,min,max,true);break;case enums_GraphicType.Rect:this.drawPoints(data,color,thickness,width,height,min,max,false);break}}}drawLine(data,color,thickness,width,height,min,max){const{gl,lineProgram,vertexBuffer}=this.state;if(!gl||!lineProgram||!vertexBuffer||!this.lineUniforms||!this.lineAttribs)return;const len=data.length;const per=width/len;gl.useProgram(lineProgram);this.setUniformsCached(gl,this.lineUniforms,color,width,height,min,max);gl.lineWidth(thickness);let segmentStart=0;let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0!==value&&!Number.isNaN(value)&&Number.isFinite(value)){const x=(i+.5)*per;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=value}else if(vertexCount>segmentStart){this.uploadAndDrawLineStrip(gl,vertexBuffer,this.lineAttribs.position,segmentStart,vertexCount);segmentStart=vertexCount}}if(vertexCount>segmentStart)this.uploadAndDrawLineStrip(gl,vertexBuffer,this.lineAttribs.position,segmentStart,vertexCount)}uploadAndDrawLineStrip(gl,vertexBuffer,positionLoc,start,end){const count=(end-start)/2;if(count<2)return;gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,this.vertexDataBuffer.subarray(start,end),gl.DYNAMIC_DRAW);gl.enableVertexAttribArray(positionLoc);gl.vertexAttribPointer(positionLoc,2,gl.FLOAT,false,0,0);gl.drawArrays(gl.LINE_STRIP,0,count)}drawStepline(data,color,thickness,width,height,min,max){const{gl,lineProgram,vertexBuffer}=this.state;if(!gl||!lineProgram||!vertexBuffer||!this.lineUniforms||!this.lineAttribs)return;const len=data.length;const per=width/len;gl.useProgram(lineProgram);this.setUniformsCached(gl,this.lineUniforms,color,width,height,min,max);gl.lineWidth(thickness);let segmentStart=0;let vertexCount=0;let prevY=0;let hasData=false;for(let i=0;i<len;i++){const value=data[i];if(void 0!==value&&!Number.isNaN(value)&&Number.isFinite(value)){const x=i*per;if(hasData){this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=prevY}this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=value;prevY=value;hasData=true}else if(hasData){const lastX=this.vertexDataBuffer[vertexCount-2];this.vertexDataBuffer[vertexCount++]=lastX+per;this.vertexDataBuffer[vertexCount++]=prevY;this.uploadAndDrawLineStrip(gl,vertexBuffer,this.lineAttribs.position,segmentStart,vertexCount);segmentStart=vertexCount;hasData=false}}if(hasData&&vertexCount>segmentStart){const lastX=this.vertexDataBuffer[vertexCount-2];this.vertexDataBuffer[vertexCount++]=lastX+per;this.vertexDataBuffer[vertexCount++]=prevY;this.uploadAndDrawLineStrip(gl,vertexBuffer,this.lineAttribs.position,segmentStart,vertexCount)}}drawBar(data,color,width,height,min,max,orientation){const{gl,fillProgram,vertexBuffer,barValue2Color,CI}=this.state;if(!gl||!fillProgram||!vertexBuffer)return;const len=data.length;if(orientation===enums_OrientationType.Horizontal){const h=height/len;let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0===value||Number.isNaN(value))continue;const yPixel=i*height/len;const barWidth=(value-min)/(max-min)*width;this.vertexDataBuffer[vertexCount++]=width-barWidth;this.vertexDataBuffer[vertexCount++]=yPixel;this.vertexDataBuffer[vertexCount++]=width;this.vertexDataBuffer[vertexCount++]=yPixel;this.vertexDataBuffer[vertexCount++]=width-barWidth;this.vertexDataBuffer[vertexCount++]=yPixel+h;this.vertexDataBuffer[vertexCount++]=width-barWidth;this.vertexDataBuffer[vertexCount++]=yPixel+h;this.vertexDataBuffer[vertexCount++]=width;this.vertexDataBuffer[vertexCount++]=yPixel;this.vertexDataBuffer[vertexCount++]=width;this.vertexDataBuffer[vertexCount++]=yPixel+h}if(0===vertexCount)return;this.drawFilledTrianglesCached(vertexCount,color,width,height,0,height)}else if(barValue2Color&&CI&&this.fillProgramWithColor)this.drawBarWithColor(data,width,height,min,max,CI);else{let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0===value||Number.isNaN(value))continue;const startX=Math.floor(i*width/len);const endX=Math.floor((i+1)*width/len);const barW=endX-startX;this.vertexDataBuffer[vertexCount++]=startX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=startX+barW;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=startX;this.vertexDataBuffer[vertexCount++]=value;this.vertexDataBuffer[vertexCount++]=startX;this.vertexDataBuffer[vertexCount++]=value;this.vertexDataBuffer[vertexCount++]=startX+barW;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=startX+barW;this.vertexDataBuffer[vertexCount++]=value}if(0===vertexCount)return;this.drawFilledTrianglesCached(vertexCount,color,width,height,min,max)}}drawBarWithColor(data,width,height,min,max,CI){const{gl,vertexBuffer}=this.state;const program=this.fillProgramWithColor;if(!gl||!program||!vertexBuffer||!this.fillColorUniforms||!this.fillColorAttribs)return;const len=data.length;let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0===value||Number.isNaN(value))continue;const startX=Math.floor(i*width/len);const endX=Math.floor((i+1)*width/len);const barW=endX-startX;const rgba=CI.getColor(value);const r=rgba.r/255;const g=rgba.g/255;const b=rgba.b/255;const a=rgba.a/255;const vertices=[startX,min,r,g,b,a,startX+barW,min,r,g,b,a,startX,value,r,g,b,a,startX,value,r,g,b,a,startX+barW,min,r,g,b,a,startX+barW,value,r,g,b,a];for(const v of vertices)this.vertexColorBuffer[vertexCount++]=v}if(0===vertexCount)return;gl.useProgram(program);gl.uniform2f(this.fillColorUniforms.resolution,width,height);gl.uniform1f(this.fillColorUniforms.rangeMin,min);gl.uniform1f(this.fillColorUniforms.rangeMax,max);gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,this.vertexColorBuffer.subarray(0,vertexCount),gl.DYNAMIC_DRAW);const stride=24;gl.enableVertexAttribArray(this.fillColorAttribs.position);gl.vertexAttribPointer(this.fillColorAttribs.position,2,gl.FLOAT,false,stride,0);gl.enableVertexAttribArray(this.fillColorAttribs.color);gl.vertexAttribPointer(this.fillColorAttribs.color,4,gl.FLOAT,false,stride,8);gl.drawArrays(gl.TRIANGLES,0,vertexCount/6)}drawArea(data,color,width,height,min,max){const{gl,fillProgram,vertexBuffer}=this.state;if(!gl||!fillProgram||!vertexBuffer)return;const len=data.length;const per=width/len;let vertexCount=0;let prevX=0;let prevY=0;let hasData=false;for(let i=0;i<len;i++){const value=data[i];if(void 0!==value&&!Number.isNaN(value)&&Number.isFinite(value)){const x=i*per;if(hasData){this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=prevY}prevX=x;prevY=value;hasData=true}else if(hasData){const endX=prevX+per;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=prevY;hasData=false}}if(hasData){const endX=prevX+per;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=prevY}if(0===vertexCount)return;this.drawFilledTrianglesCached(vertexCount,color,width,height,min,max)}drawPoints(data,color,thickness,width,height,min,max,isCircle){const{gl,vertexBuffer}=this.state;const program=isCircle?this.pointCircleProgram:this.pointRectProgram;const uniforms=isCircle?this.pointCircleUniforms:this.pointRectUniforms;const attribs=isCircle?this.pointCircleAttribs:this.pointRectAttribs;if(!gl||!program||!vertexBuffer||!uniforms||!attribs)return;const len=data.length;const per=width/len;let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0!==value&&!Number.isNaN(value)&&Number.isFinite(value)){const x=(i+.5)*per;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=value}}if(0===vertexCount)return;const{r,g,b,a}=hexToRGBA(color);gl.useProgram(program);gl.uniform2f(uniforms.resolution,width,height);gl.uniform1f(uniforms.rangeMin,min);gl.uniform1f(uniforms.rangeMax,max);gl.uniform4f(uniforms.color,r/255,g/255,b/255,a/255);gl.uniform1f(uniforms.pointSize,thickness);gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,this.vertexDataBuffer.subarray(0,vertexCount),gl.DYNAMIC_DRAW);gl.enableVertexAttribArray(attribs.position);gl.vertexAttribPointer(attribs.position,2,gl.FLOAT,false,0,0);gl.drawArrays(gl.POINTS,0,vertexCount/2)}drawFilledTrianglesCached(vertexCount,color,width,height,min,max){const{gl,fillProgram,vertexBuffer}=this.state;if(!gl||!fillProgram||!vertexBuffer||!this.fillUniforms||!this.fillAttribs||0===vertexCount)return;gl.useProgram(fillProgram);this.setUniformsCached(gl,this.fillUniforms,color,width,height,min,max);gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,this.vertexDataBuffer.subarray(0,vertexCount),gl.DYNAMIC_DRAW);gl.enableVertexAttribArray(this.fillAttribs.position);gl.vertexAttribPointer(this.fillAttribs.position,2,gl.FLOAT,false,0,0);gl.drawArrays(gl.TRIANGLES,0,vertexCount/2)}setUniformsCached(gl,uniforms,color,width,height,min,max){const{r,g,b,a}=hexToRGBA(color);gl.uniform2f(uniforms.resolution,width,height);gl.uniform1f(uniforms.rangeMin,min);gl.uniform1f(uniforms.rangeMax,max);gl.uniform4f(uniforms.color,r/255,g/255,b/255,a/255)}resize(){super.resize()}dispose(){const{gl,lineProgram,fillProgram,pointProgram,vertexBuffer,colorTexture}=this.state;if(gl){if(lineProgram)gl.deleteProgram(lineProgram);if(fillProgram)gl.deleteProgram(fillProgram);if(pointProgram)gl.deleteProgram(pointProgram);if(this.fillProgramWithColor)gl.deleteProgram(this.fillProgramWithColor);if(this.pointCircleProgram)gl.deleteProgram(this.pointCircleProgram);if(this.pointRectProgram)gl.deleteProgram(this.pointRectProgram);if(vertexBuffer)gl.deleteBuffer(vertexBuffer);if(colorTexture)gl.deleteTexture(colorTexture)}super.dispose()}}export{ColorInterpolator,Dial,Fluorescence,Gauge,enums_GraphicType as GraphicType,cartesian_Heatmap as Heatmap,HeatmapCanvas,HeatmapWebGL,IQ,IQEye,enums_OrientationType as OrientationType,Radar,enums_RendererType as RendererType,Series,SeriesWebGL,color2intensity,createHeatmap,hexToRGBA,rgbToHex};
|
|
120
|
+
`;class SeriesWebGL extends WebGLEngine{fillProgramWithColor=null;pointCircleProgram=null;pointRectProgram=null;lineUniforms=null;lineAttribs=null;fillUniforms=null;fillAttribs=null;fillColorUniforms=null;fillColorAttribs=null;pointCircleUniforms=null;pointCircleAttribs=null;pointRectUniforms=null;pointRectAttribs=null;vertexDataBuffer=new Float32Array(MAX_VERTICES);vertexColorBuffer=new Float32Array(MAX_VERTICES);init(props){super.init(props);const{gl}=this.state;if(!gl)return;const{series,barValue2Color,disabledClearRect,colors=[]}=props;const lineProgram=this.createProgram({vertex:SeriesWebGL_VERTEX_SHADER,fragment:SeriesWebGL_FRAGMENT_SHADER});const fillProgram=this.createProgram({vertex:SeriesWebGL_VERTEX_SHADER,fragment:SeriesWebGL_FRAGMENT_SHADER});this.fillProgramWithColor=this.createProgram({vertex:VERTEX_SHADER_WITH_COLOR,fragment:FRAGMENT_SHADER_WITH_COLOR});const pointProgram=this.createProgram({vertex:POINT_VERTEX_SHADER,fragment:POINT_CIRCLE_FRAGMENT_SHADER});this.pointCircleProgram=pointProgram;this.pointRectProgram=this.createProgram({vertex:POINT_VERTEX_SHADER,fragment:POINT_RECT_FRAGMENT_SHADER});this.cacheLocations(gl,lineProgram,fillProgram);const vertexBuffer=gl.createBuffer();const CI=barValue2Color&&colors.length>0?new ColorInterpolator(colors,0,100,.1):null;const colorTexture=this.createTexture();this.updateProps({series:{},colors,interval:props.interval??0,barValue2Color,disabledClearRect,lineProgram,fillProgram,pointProgram,vertexBuffer,colorTexture,CI});if(Array.isArray(series))series.forEach(e=>{this.setSeries(e)});gl.enable(gl.BLEND);gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA)}cacheLocations(gl,lineProgram,fillProgram){if(lineProgram){this.lineUniforms={resolution:gl.getUniformLocation(lineProgram,"u_resolution"),rangeMin:gl.getUniformLocation(lineProgram,"u_rangeMin"),rangeMax:gl.getUniformLocation(lineProgram,"u_rangeMax"),color:gl.getUniformLocation(lineProgram,"u_color")};this.lineAttribs={position:gl.getAttribLocation(lineProgram,"a_position")}}if(fillProgram){this.fillUniforms={resolution:gl.getUniformLocation(fillProgram,"u_resolution"),rangeMin:gl.getUniformLocation(fillProgram,"u_rangeMin"),rangeMax:gl.getUniformLocation(fillProgram,"u_rangeMax"),color:gl.getUniformLocation(fillProgram,"u_color")};this.fillAttribs={position:gl.getAttribLocation(fillProgram,"a_position")}}if(this.fillProgramWithColor){this.fillColorUniforms={resolution:gl.getUniformLocation(this.fillProgramWithColor,"u_resolution"),rangeMin:gl.getUniformLocation(this.fillProgramWithColor,"u_rangeMin"),rangeMax:gl.getUniformLocation(this.fillProgramWithColor,"u_rangeMax"),color:null};this.fillColorAttribs={position:gl.getAttribLocation(this.fillProgramWithColor,"a_position"),color:gl.getAttribLocation(this.fillProgramWithColor,"a_color")}}if(this.pointCircleProgram){this.pointCircleUniforms={resolution:gl.getUniformLocation(this.pointCircleProgram,"u_resolution"),rangeMin:gl.getUniformLocation(this.pointCircleProgram,"u_rangeMin"),rangeMax:gl.getUniformLocation(this.pointCircleProgram,"u_rangeMax"),color:gl.getUniformLocation(this.pointCircleProgram,"u_color"),pointSize:gl.getUniformLocation(this.pointCircleProgram,"u_pointSize")};this.pointCircleAttribs={position:gl.getAttribLocation(this.pointCircleProgram,"a_position")}}if(this.pointRectProgram){this.pointRectUniforms={resolution:gl.getUniformLocation(this.pointRectProgram,"u_resolution"),rangeMin:gl.getUniformLocation(this.pointRectProgram,"u_rangeMin"),rangeMax:gl.getUniformLocation(this.pointRectProgram,"u_rangeMax"),color:gl.getUniformLocation(this.pointRectProgram,"u_color"),pointSize:gl.getUniformLocation(this.pointRectProgram,"u_pointSize")};this.pointRectAttribs={position:gl.getAttribLocation(this.pointRectProgram,"a_position")}}}updateProps(e){super.updateProps(e);const{colors=this.state.colors}=e;if(this.state.barValue2Color&&!this.state.CI&&colors?.length>0)this.state.CI=new ColorInterpolator(colors,0,100,.1)}clear(){this.clearRect();const{series}=this.state;const seriesArray=Object.entries(series);seriesArray.forEach(([name,i])=>{this.setSeries({...i,name,data:void 0})})}setRange(range){this.updateProps({range:[range[0],range[1],range[1]-range[0]]});this.draw()}setIntervel(interval){if(!interval)return;this.updateProps({interval})}setSeries(e){if(e?.name){const{name}=e;const{series}=this.state;series[name]={thickness:1,display:true,color:"#000000",type:enums_GraphicType.Line,data:void 0,orientation:enums_OrientationType.Vertical,...series[name],...e};this.draw()}}render(e){e&&this.setSeries(e);this.draw()}draw(){const{gl,series,disabledClearRect,range,canvas}=this.state;if(!gl)return;if(!disabledClearRect)this.clearRect();const seriesArray=Object.values(series);const min=range[0];const max=range[1];const{width,height}=canvas;for(const seriesItem of seriesArray){const{display,type,data,orientation}=seriesItem;const thickness=seriesItem.thickness??DEFAULTS.THICKNESS;const color=seriesItem.color??DEFAULTS.COLOR;if(!!data&&!!display)switch(type){case enums_GraphicType.Line:this.drawLine(data,color,thickness,width,height,min,max);break;case enums_GraphicType.Stepline:this.drawStepline(data,color,thickness,width,height,min,max);break;case enums_GraphicType.Bar:this.drawBar(data,color,width,height,min,max,orientation??enums_OrientationType.Vertical);break;case enums_GraphicType.Area:this.drawArea(data,color,width,height,min,max);break;case enums_GraphicType.Circle:this.drawPoints(data,color,thickness,width,height,min,max,true);break;case enums_GraphicType.Rect:this.drawPoints(data,color,thickness,width,height,min,max,false);break}}}drawLine(data,color,thickness,width,height,min,max){const{gl,lineProgram,vertexBuffer}=this.state;if(!gl||!lineProgram||!vertexBuffer||!this.lineUniforms||!this.lineAttribs)return;const len=data.length;const per=width/len;gl.useProgram(lineProgram);this.setUniformsCached(gl,this.lineUniforms,color,width,height,min,max);gl.lineWidth(thickness);let segmentStart=0;let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0!==value&&!Number.isNaN(value)&&Number.isFinite(value)){const x=(i+.5)*per;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=value}else if(vertexCount>segmentStart){this.uploadAndDrawLineStrip(gl,vertexBuffer,this.lineAttribs.position,segmentStart,vertexCount);segmentStart=vertexCount}}if(vertexCount>segmentStart)this.uploadAndDrawLineStrip(gl,vertexBuffer,this.lineAttribs.position,segmentStart,vertexCount)}uploadAndDrawLineStrip(gl,vertexBuffer,positionLoc,start,end){const count=(end-start)/2;if(count<2)return;gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,this.vertexDataBuffer.subarray(start,end),gl.DYNAMIC_DRAW);gl.enableVertexAttribArray(positionLoc);gl.vertexAttribPointer(positionLoc,2,gl.FLOAT,false,0,0);gl.drawArrays(gl.LINE_STRIP,0,count)}drawStepline(data,color,thickness,width,height,min,max){const{gl,lineProgram,vertexBuffer}=this.state;if(!gl||!lineProgram||!vertexBuffer||!this.lineUniforms||!this.lineAttribs)return;const len=data.length;const per=width/len;gl.useProgram(lineProgram);this.setUniformsCached(gl,this.lineUniforms,color,width,height,min,max);gl.lineWidth(thickness);let segmentStart=0;let vertexCount=0;let prevY=0;let hasData=false;for(let i=0;i<len;i++){const value=data[i];if(void 0!==value&&!Number.isNaN(value)&&Number.isFinite(value)){const x=i*per;if(hasData){this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=prevY}this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=value;prevY=value;hasData=true}else if(hasData){const lastX=this.vertexDataBuffer[vertexCount-2];this.vertexDataBuffer[vertexCount++]=lastX+per;this.vertexDataBuffer[vertexCount++]=prevY;this.uploadAndDrawLineStrip(gl,vertexBuffer,this.lineAttribs.position,segmentStart,vertexCount);segmentStart=vertexCount;hasData=false}}if(hasData&&vertexCount>segmentStart){const lastX=this.vertexDataBuffer[vertexCount-2];this.vertexDataBuffer[vertexCount++]=lastX+per;this.vertexDataBuffer[vertexCount++]=prevY;this.uploadAndDrawLineStrip(gl,vertexBuffer,this.lineAttribs.position,segmentStart,vertexCount)}}drawBar(data,color,width,height,min,max,orientation){const{gl,fillProgram,vertexBuffer,barValue2Color,CI}=this.state;if(!gl||!fillProgram||!vertexBuffer)return;const len=data.length;if(orientation===enums_OrientationType.Horizontal){const h=height/len;let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0===value||Number.isNaN(value))continue;const yPixel=i*height/len;const barWidth=(value-min)/(max-min)*width;this.vertexDataBuffer[vertexCount++]=width-barWidth;this.vertexDataBuffer[vertexCount++]=yPixel;this.vertexDataBuffer[vertexCount++]=width;this.vertexDataBuffer[vertexCount++]=yPixel;this.vertexDataBuffer[vertexCount++]=width-barWidth;this.vertexDataBuffer[vertexCount++]=yPixel+h;this.vertexDataBuffer[vertexCount++]=width-barWidth;this.vertexDataBuffer[vertexCount++]=yPixel+h;this.vertexDataBuffer[vertexCount++]=width;this.vertexDataBuffer[vertexCount++]=yPixel;this.vertexDataBuffer[vertexCount++]=width;this.vertexDataBuffer[vertexCount++]=yPixel+h}if(0===vertexCount)return;this.drawFilledTrianglesCached(vertexCount,color,width,height,0,height)}else if(barValue2Color&&CI&&this.fillProgramWithColor)this.drawBarWithColor(data,width,height,min,max,CI);else{let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0===value||Number.isNaN(value))continue;const startX=Math.floor(i*width/len);const endX=Math.floor((i+1)*width/len);const barW=endX-startX;this.vertexDataBuffer[vertexCount++]=startX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=startX+barW;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=startX;this.vertexDataBuffer[vertexCount++]=value;this.vertexDataBuffer[vertexCount++]=startX;this.vertexDataBuffer[vertexCount++]=value;this.vertexDataBuffer[vertexCount++]=startX+barW;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=startX+barW;this.vertexDataBuffer[vertexCount++]=value}if(0===vertexCount)return;this.drawFilledTrianglesCached(vertexCount,color,width,height,min,max)}}drawBarWithColor(data,width,height,min,max,CI){const{gl,vertexBuffer}=this.state;const program=this.fillProgramWithColor;if(!gl||!program||!vertexBuffer||!this.fillColorUniforms||!this.fillColorAttribs)return;const len=data.length;let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0===value||Number.isNaN(value))continue;const startX=Math.floor(i*width/len);const endX=Math.floor((i+1)*width/len);const barW=endX-startX;const rgba=CI.getColor(value);const r=rgba.r/255;const g=rgba.g/255;const b=rgba.b/255;const a=rgba.a/255;const vertices=[startX,min,r,g,b,a,startX+barW,min,r,g,b,a,startX,value,r,g,b,a,startX,value,r,g,b,a,startX+barW,min,r,g,b,a,startX+barW,value,r,g,b,a];for(const v of vertices)this.vertexColorBuffer[vertexCount++]=v}if(0===vertexCount)return;gl.useProgram(program);gl.uniform2f(this.fillColorUniforms.resolution,width,height);gl.uniform1f(this.fillColorUniforms.rangeMin,min);gl.uniform1f(this.fillColorUniforms.rangeMax,max);gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,this.vertexColorBuffer.subarray(0,vertexCount),gl.DYNAMIC_DRAW);const stride=24;gl.enableVertexAttribArray(this.fillColorAttribs.position);gl.vertexAttribPointer(this.fillColorAttribs.position,2,gl.FLOAT,false,stride,0);gl.enableVertexAttribArray(this.fillColorAttribs.color);gl.vertexAttribPointer(this.fillColorAttribs.color,4,gl.FLOAT,false,stride,8);gl.drawArrays(gl.TRIANGLES,0,vertexCount/6)}drawArea(data,color,width,height,min,max){const{gl,fillProgram,vertexBuffer}=this.state;if(!gl||!fillProgram||!vertexBuffer)return;const len=data.length;const per=width/len;let vertexCount=0;let prevX=0;let prevY=0;let hasData=false;for(let i=0;i<len;i++){const value=data[i];if(void 0!==value&&!Number.isNaN(value)&&Number.isFinite(value)){const x=i*per;if(hasData){this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=prevY}prevX=x;prevY=value;hasData=true}else if(hasData){const endX=prevX+per;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=prevY;hasData=false}}if(hasData){const endX=prevX+per;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=prevX;this.vertexDataBuffer[vertexCount++]=prevY;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=min;this.vertexDataBuffer[vertexCount++]=endX;this.vertexDataBuffer[vertexCount++]=prevY}if(0===vertexCount)return;this.drawFilledTrianglesCached(vertexCount,color,width,height,min,max)}drawPoints(data,color,thickness,width,height,min,max,isCircle){const{gl,vertexBuffer}=this.state;const program=isCircle?this.pointCircleProgram:this.pointRectProgram;const uniforms=isCircle?this.pointCircleUniforms:this.pointRectUniforms;const attribs=isCircle?this.pointCircleAttribs:this.pointRectAttribs;if(!gl||!program||!vertexBuffer||!uniforms||!attribs)return;const len=data.length;const per=width/len;let vertexCount=0;for(let i=0;i<len;i++){const value=data[i];if(void 0!==value&&!Number.isNaN(value)&&Number.isFinite(value)){const x=(i+.5)*per;this.vertexDataBuffer[vertexCount++]=x;this.vertexDataBuffer[vertexCount++]=value}}if(0===vertexCount)return;const{r,g,b,a}=hexToRGBA(color);gl.useProgram(program);gl.uniform2f(uniforms.resolution,width,height);gl.uniform1f(uniforms.rangeMin,min);gl.uniform1f(uniforms.rangeMax,max);gl.uniform4f(uniforms.color,r/255,g/255,b/255,a/255);gl.uniform1f(uniforms.pointSize,thickness);gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,this.vertexDataBuffer.subarray(0,vertexCount),gl.DYNAMIC_DRAW);gl.enableVertexAttribArray(attribs.position);gl.vertexAttribPointer(attribs.position,2,gl.FLOAT,false,0,0);gl.drawArrays(gl.POINTS,0,vertexCount/2)}drawFilledTrianglesCached(vertexCount,color,width,height,min,max){const{gl,fillProgram,vertexBuffer}=this.state;if(!gl||!fillProgram||!vertexBuffer||!this.fillUniforms||!this.fillAttribs||0===vertexCount)return;gl.useProgram(fillProgram);this.setUniformsCached(gl,this.fillUniforms,color,width,height,min,max);gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER,this.vertexDataBuffer.subarray(0,vertexCount),gl.DYNAMIC_DRAW);gl.enableVertexAttribArray(this.fillAttribs.position);gl.vertexAttribPointer(this.fillAttribs.position,2,gl.FLOAT,false,0,0);gl.drawArrays(gl.TRIANGLES,0,vertexCount/2)}setUniformsCached(gl,uniforms,color,width,height,min,max){const{r,g,b,a}=hexToRGBA(color);gl.uniform2f(uniforms.resolution,width,height);gl.uniform1f(uniforms.rangeMin,min);gl.uniform1f(uniforms.rangeMax,max);gl.uniform4f(uniforms.color,r/255,g/255,b/255,a/255)}resize(){super.resize()}dispose(){const{gl,lineProgram,fillProgram,pointProgram,vertexBuffer,colorTexture}=this.state;if(gl){if(lineProgram)gl.deleteProgram(lineProgram);if(fillProgram)gl.deleteProgram(fillProgram);if(pointProgram)gl.deleteProgram(pointProgram);if(this.fillProgramWithColor)gl.deleteProgram(this.fillProgramWithColor);if(this.pointCircleProgram)gl.deleteProgram(this.pointCircleProgram);if(this.pointRectProgram)gl.deleteProgram(this.pointRectProgram);if(vertexBuffer)gl.deleteBuffer(vertexBuffer);if(colorTexture)gl.deleteTexture(colorTexture)}super.dispose()}}const ENABLE_AREA_GRADIENT=false;class SeriesCanvas extends Engine{init(props){super.init(props);const{series,barValue2Color,disabledClearRect,colors}=props;this.updateProps({interval:0,series:{},barValue2Color,disabledClearRect,colors});this.setRange(this.state.range);if(Array.isArray(series))series.forEach(e=>{this.setSeries(e)})}updateProps(e){super.updateProps(e);const{colors=this.state.colors}=e;if(this.state.barValue2Color&&!this.state.CI&&colors)this.updateProps({CI:new ColorInterpolator(colors,0,100,.1)})}clear(){super.clearRect();const{series}=this.state;const seriesArray=Object.entries(series);seriesArray.forEach(([name,i])=>{this.setSeries({...i,name,data:void 0})})}setRange(range){this.updateProps({range:[range[0],range[1],range[1]-range[0]]});this.draw()}setIntervel(interval){if(!interval)return;this.updateProps({interval})}setSeries(e){if(e?.name){const{name}=e;const{series}=this.state;series[name]={thickness:1,display:true,color:"#000000",type:enums_GraphicType.Line,data:void 0,path:void 0,orientation:enums_OrientationType.Vertical,...series[name],...e};this.draw()}}render(e){e&&this.setSeries(e);this.draw()}draw(){const{series,ctx,disabledClearRect}=this.state;if(!disabledClearRect)this.clearRect();const seriesArray=Object.values(series);const{range,canvas}=this.state;const min=range[0];const max=range[1];const{width,height}=canvas;const rangeY=max-min;ctx.save();ctx.translate(.5,.5);for(let s=0;s<seriesArray.length;s+=1){const seriesItem=seriesArray[s];const{display,type,data,orientation}=seriesItem;const thickness=seriesItem.thickness??DEFAULTS.THICKNESS;const color=seriesItem.color??DEFAULTS.COLOR;if(!data||!display)continue;const len=data.length;const per=width/len;switch(type){case enums_GraphicType.Line:case enums_GraphicType.Stepline:ctx.lineWidth=thickness;ctx.strokeStyle=color;break;case enums_GraphicType.Circle:case enums_GraphicType.Rect:case enums_GraphicType.Bar:case enums_GraphicType.Area:ctx.fillStyle=color;break}if(type===enums_GraphicType.Line){let points=[];for(let i=0;i<len;i+=1){const value=data[i];if(void 0===value||Number.isNaN(value)){if(points.length>0){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let j=1;j<points.length;j++)ctx.lineTo(points[j][0],points[j][1]);ctx.lineWidth=thickness;ctx.strokeStyle=color;ctx.stroke();points=[]}}else{const x=Math.round((i+.5)*per);const y=Math.round((value-min)/rangeY*height);points.push([x,y])}}if(points.length>0){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let j=1;j<points.length;j++)ctx.lineTo(points[j][0],points[j][1]);ctx.lineWidth=thickness;ctx.strokeStyle=color;ctx.stroke()}}if(type===enums_GraphicType.Stepline){let points=[];for(let i=0;i<len;i+=1){const value=data[i];if(void 0===value||Number.isNaN(value)){if(points.length>0){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let j=1;j<points.length;j++){const[_,py]=points[j-1];const[cx,cy]=points[j];ctx.lineTo(cx,py);ctx.lineTo(cx,cy)}const[lx,ly]=points[points.length-1];const endX=Math.round(lx+per);ctx.lineTo(endX,ly);ctx.lineWidth=thickness;ctx.strokeStyle=color;ctx.stroke();points=[]}}else{const x=Math.round(i*per);const y=Math.round((value-min)/rangeY*height);points.push([x,y])}}if(points.length>0){ctx.beginPath();ctx.moveTo(points[0][0],points[0][1]);for(let j=1;j<points.length;j++){const[_,py]=points[j-1];const[cx,cy]=points[j];ctx.lineTo(cx,py);ctx.lineTo(cx,cy)}const[lx,ly]=points[points.length-1];const endX=Math.round(lx+per);ctx.lineTo(endX,ly);ctx.lineWidth=thickness;ctx.strokeStyle=color;ctx.stroke()}}if(type===enums_GraphicType.Circle){const radius=+thickness/2;const endAngle=2*Math.PI;for(let i=0;i<len;i+=1){const x=Math.round((i+.5)*per);const y=Math.round((data[i]-min)/rangeY*height);ctx.beginPath();ctx.arc(x,y,radius,0,endAngle);ctx.fillStyle=color;ctx.fill()}}if(type===enums_GraphicType.Rect){const side=+thickness;for(let i=0;i<len;i+=1){const x=Math.round((i+.5)*per);const y=Math.round((data[i]-min)/rangeY*height);ctx.beginPath();ctx.rect(x,y,side,side);ctx.fillStyle=color;ctx.fill()}}if(type===enums_GraphicType.Area){let points=[];const{r,g,b}=hexToRGBA(color??"#000000");const drawArea=pointsToDraw=>{if(0===pointsToDraw.length)return;const[firstX,firstY]=pointsToDraw[0];const[lastX,lastY]=pointsToDraw[pointsToDraw.length-1];const endX=Math.round(lastX+per);ctx.beginPath();ctx.moveTo(firstX,0);ctx.lineTo(firstX,firstY);for(let j=1;j<pointsToDraw.length;j++){const[_,prevY]=pointsToDraw[j-1];const[currX,currY]=pointsToDraw[j];ctx.lineTo(currX,prevY);ctx.lineTo(currX,currY)}ctx.lineTo(endX,lastY);ctx.lineTo(endX,0);ctx.closePath();if(ENABLE_AREA_GRADIENT){const gradient=ctx.createLinearGradient(0,0,0,height);gradient.addColorStop(0,`rgba(${r}, ${g}, ${b}, 0)`);gradient.addColorStop(1,`rgba(${r}, ${g}, ${b}, 0.5)`);ctx.fillStyle=gradient}else ctx.fillStyle=`rgba(${r}, ${g}, ${b}, 1)`;ctx.fill()};for(let i=0;i<len;i+=1){const value=data[i];if(void 0===value||Number.isNaN(value)){drawArea(points);points=[]}else points.push([Math.round(i*per),Math.round((value-min)/rangeY*height)])}drawArea(points)}if(type===enums_GraphicType.Bar){if(orientation===enums_OrientationType.Horizontal){const h=height/len;const hh=Math.round(h);for(let i=0;i<len;i+=1){const y=Math.round(height-(i+1)*h);const w=Math.round((data[i]-min)/rangeY*width);const x=width-w;ctx.beginPath();ctx.rect(x,y,w,hh);ctx.fillStyle=color;ctx.fill()}}else for(let i=0;i<len;i+=1){const startX=Math.floor(i*width/len);const endX=Math.floor((i+1)*width/len);const w=endX-startX;const h=Math.round((data[i]-min)/rangeY*height);ctx.beginPath();ctx.rect(startX,0,w,h);ctx.fillStyle=this.state.barValue2Color?this.state.CI?.getColor(data[i]).hax??color:color;ctx.fill()}}}ctx.restore()}}function createSeries(props){const{renderer=enums_RendererType.Canvas}=props;if(renderer===enums_RendererType.WebGL)return new SeriesWebGL(props);return new SeriesCanvas(props)}const Series_Series=function(props){return createSeries(props)};const cartesian_Series=Series_Series;function getCoordinates(radius,padding,angle){const x=radius+(radius-padding)*Math.cos(angle);const y=radius+(radius-padding)*Math.sin(angle);return[x,y]}class CircularBase extends Engine{getSpecialTickConfig(_angle){}getAngleOffset(){return 0}init(props){super.init(props);this.state.canvas.style.transform="scaleY(1)";const fillStyle=props.fillStyle??DEFAULTS.FILL_STYLE;const fillStylePrimary=props.fillStylePrimary??DEFAULTS.FILL_STYLE_PRIMARY;const fillStyleTransparentBase=props.fillStyleTransparentBase??DEFAULTS.FILL_STYLE_TRANSPARENT_BASE;const markedNum=12;const baseWidth=6;this.updateProps({fillStyle,fillStylePrimary,fillStyleTransparentBase,baseWidth,padding:10*baseWidth,ticksStep:6,ticksRenderLength:5,markedAngles:Array.from({length:markedNum},(_,i)=>360/markedNum*i),color2intensity:color2intensity(fillStylePrimary),data:{series:[],range:[0,0],yawAngle:0,isNorthFacing:true}})}clear(){this.clearRect()}resize(){super.resize();if(this.state.markedAngles)this.drawBackground();if(this.state.data)this.drawTicks()}render(data){const isYawAngleChange=void 0!==data.yawAngle&&data.yawAngle!==this.state.data?.yawAngle;this.state.data={...this.state.data,...data};if(isYawAngleChange)this.drawTicks();this.draw()}drawTicks(){const{canvas,baseWidth,fillStyle,fillStylePrimary,ticksStep,ticksRenderLength,markedAngles,data}=this.state;const{yawAngle=0,isNorthFacing=true}=data;const ticksCanvas=document.createElement("canvas");ticksCanvas.width=canvas.width;ticksCanvas.height=canvas.height;const ticksCtx=ticksCanvas.getContext("2d");if(!ticksCtx)return;const radius=canvas.width/2;const northYawgle=isNorthFacing?0:-yawAngle;for(let i=0;i<360;i+=ticksStep){const angle=(i+northYawgle)*Math.PI/180;const isMarked=markedAngles.includes(i);const length=ticksRenderLength*(isMarked?1.2:1);const[x,y]=getCoordinates(radius,3.5*baseWidth+length+(isMarked?3:0),angle);const[xOuter,yOuter]=getCoordinates(radius,3.5*baseWidth,angle);ticksCtx.beginPath();ticksCtx.moveTo(x,y);ticksCtx.lineTo(xOuter,yOuter);ticksCtx.strokeStyle=fillStyle;ticksCtx.lineWidth=isMarked?2:.5;ticksCtx.stroke()}ticksCtx.font=`${2*baseWidth}px Arial`;ticksCtx.textAlign="center";ticksCtx.textBaseline="middle";markedAngles.forEach(angle=>{const radian=(angle+northYawgle-90)*Math.PI/180;const[x,y]=getCoordinates(radius,8*baseWidth,radian);const specialConfig=this.getSpecialTickConfig(angle);if(specialConfig){ticksCtx.fillStyle=specialConfig.color;ticksCtx.fillText(specialConfig.alias,x,y)}else{ticksCtx.fillStyle=fillStyle;ticksCtx.fillText(angle.toString(),x,y)}});const arrowWidth=canvas.width/18;ticksCtx.translate(canvas.width/2,canvas.height/2);ticksCtx.scale(1,-1);ticksCtx.rotate((isNorthFacing?-yawAngle:0)*Math.PI/180);ticksCtx.lineJoin="round";ticksCtx.lineCap="round";ticksCtx.strokeStyle=fillStylePrimary;ticksCtx.fillStyle=fillStylePrimary;ticksCtx.lineWidth=arrowWidth/6;ticksCtx.beginPath();ticksCtx.moveTo(0,arrowWidth/2);ticksCtx.lineTo(arrowWidth/2,-arrowWidth/2);ticksCtx.lineTo(0,arrowWidth/2-1/((1+Math.sqrt(5))/2)*arrowWidth);ticksCtx.lineTo(-arrowWidth/2,-arrowWidth/2);ticksCtx.lineTo(0,arrowWidth/2);ticksCtx.fill();ticksCtx.stroke();this.state.ticksCanvas=ticksCanvas}drawBackground(){const{canvas,baseWidth,padding,fillStyleTransparentBase}=this.state;const BGCanvas=document.createElement("canvas");BGCanvas.width=canvas.width;BGCanvas.height=canvas.height;const BGCtx=BGCanvas.getContext("2d");if(!BGCtx)return;const radius=canvas.width/2;BGCtx.beginPath();BGCtx.arc(radius,radius,radius-2*baseWidth,0,2*Math.PI);BGCtx.strokeStyle=fillStyleTransparentBase;BGCtx.lineWidth=baseWidth;BGCtx.stroke();new Array(5).fill(1).forEach((_,i)=>{BGCtx.beginPath();BGCtx.arc(radius,radius,(radius-padding)*(i+1)/5,0,2*Math.PI);BGCtx.strokeStyle=fillStyleTransparentBase;BGCtx.lineWidth=baseWidth/4;BGCtx.stroke()});this.state.BGCanvas=BGCanvas}draw(){const{data,canvas,ctx,baseWidth,padding,BGCanvas,ticksCanvas,color2intensity:c2i,fillStyleTransparentBase}=this.state;const{series,range,isNorthFacing=true,yawAngle=0}=data;if(!series)return;this.clearRect();const radius=canvas.width/2;const northYawgle=isNorthFacing?0:-yawAngle;const angleOffset=this.getAngleOffset();if(BGCanvas)ctx.drawImage(BGCanvas,0,0);if(range){const sliceAngle=360/range.length;range.forEach((value,index)=>{const startAngle=(index*sliceAngle+northYawgle+angleOffset)*Math.PI/180;const endAngle=((index+1)*sliceAngle+northYawgle+angleOffset)*Math.PI/180;ctx.beginPath();ctx.moveTo(radius,radius);ctx.arc(radius,radius,radius-padding,startAngle,endAngle);ctx.closePath();ctx.fillStyle=c2i[value];ctx.fill()})}series.forEach(({value,color,lineWidth=baseWidth,radio=1})=>{if(null==value)return;const pointerAngle=(value+northYawgle)*Math.PI/180-Math.PI/2;const[startX,startY]=getCoordinates(radius,radius,pointerAngle);const[endX,endY]=getCoordinates(radius,padding+(1-radio)*(radius-padding)+lineWidth/2,pointerAngle);if(1!==radio){ctx.beginPath();ctx.moveTo(...getCoordinates(radius,padding+lineWidth/2,pointerAngle));ctx.lineTo(endX,endY);ctx.strokeStyle=fillStyleTransparentBase;ctx.stroke()}ctx.beginPath();ctx.moveTo(endX,endY);ctx.lineTo(startX,startY);ctx.strokeStyle=color;ctx.lineWidth=lineWidth;ctx.lineJoin="round";ctx.lineCap="round";ctx.stroke()});if(ticksCanvas)ctx.drawImage(ticksCanvas,0,0)}}const SPECIAL_TICK_CONFIG={0:{color:"#ff4d4f",alias:"北"},180:{color:"#1890ff",alias:"南"}};class Dial extends CircularBase{getSpecialTickConfig(angle){return SPECIAL_TICK_CONFIG[angle]}getAngleOffset(){return -90}}class Radar extends CircularBase{getSpecialTickConfig(_angle){}getAngleOffset(){return 0}}class IQ extends Engine{init(props){super.init(props);this.updateProps({lineColor:props.lineColor??DEFAULTS.LINE_COLOR,pointColor:props.pointColor??DEFAULTS.POINT_COLOR})}clear(){this.clearRect();this.updateProps({data:{IData:[],QData:[]}})}render(data){if(data.IData&&data.QData){this.state.data=data;this.draw()}}draw(){const{data,canvas,pointColor,lineColor,ctx}=this.state;if(!data)return;const{IData,QData}=data;if(0===IData.length||0===QData.length)return;const{width,height}=ctx.canvas;ctx.clearRect(0,0,canvas.width,canvas.height);const[minX,maxX]=getMinMax(IData);const[minY,maxY]=getMinMax([minX,maxX,...QData]);const xScale=width/(maxX-minX);const yScale=height/(maxY-minY);const pointRadius=2;const points=IData.map((xVal,i)=>{const x=(xVal-minX)*xScale;const y=(QData[i]-minY)*yScale;return{x,y}});ctx.beginPath();points.forEach((point,i)=>{ctx[0===i?"moveTo":"lineTo"](point.x,point.y)});ctx.strokeStyle=lineColor;ctx.lineWidth=1;ctx.stroke();points.forEach(point=>{ctx.beginPath();ctx.arc(point.x,point.y,pointRadius,0,2*Math.PI);ctx.fillStyle=pointColor;ctx.fill()})}}const EYE_CONFIG={Y_RANGE:{MIN:-1,MAX:1},SEGMENT_SIZE:5};class IQEye extends Engine{init(props){super.init(props);this.updateProps({lineColor:props.lineColor??DEFAULTS.LINE_COLOR,pointColor:props.pointColor??DEFAULTS.POINT_COLOR})}clear(){this.clearRect();this.updateProps({data:{IData:[],QData:[]}})}render(data){if(data.IData&&data.QData){this.state.data=data;this.draw()}}draw(){if(!this.state.data)return;const{data:{IData,QData},ctx,canvas}=this.state;if(0===IData.length||0===QData.length)return;this.clearRect();const min=EYE_CONFIG.Y_RANGE.MIN;const rangeY=EYE_CONFIG.Y_RANGE.MAX-EYE_CONFIG.Y_RANGE.MIN;const{width,height}=canvas;const offscreenCanvas=document.createElement("canvas");offscreenCanvas.width=width;offscreenCanvas.height=height;const offCtx=offscreenCanvas.getContext("2d",{willReadFrequently:true});if(!offCtx)return;this.drawAllSegments(IData,QData,min,rangeY,width,height,offCtx);const imageData=offCtx.getImageData(0,0,width,height);const data=imageData.data;this.applyColorGradient(data);ctx.putImageData(imageData,0,0)}drawAllSegments(iData,qData,min,rangeY,width,height,ctx){ctx.clearRect(0,0,width,height);const accumulator=new Uint8Array(width*height);this.drawSegmentedData(iData,min,rangeY,width,height,accumulator);this.drawSegmentedData(qData,min,rangeY,width,height,accumulator);const imageData=ctx.getImageData(0,0,width,height);const data=imageData.data;for(let i=0;i<accumulator.length;i++)if(accumulator[i]>0){const index=4*i;data[index]=255;data[index+1]=255;data[index+2]=255;data[index+3]=Math.min(50*accumulator[i],255)}ctx.putImageData(imageData,0,0)}applyColorGradient(data){const{lineColor,pointColor}=this.state;const startColor=parseColor(lineColor);const endColor=parseColor(pointColor);for(let i=0;i<data.length;i+=4)if(data[i+3]>0){const intensity=data[i+3]/255;data[i]=Math.round(startColor.r+(endColor.r-startColor.r)*intensity);data[i+1]=Math.round(startColor.g+(endColor.g-startColor.g)*intensity);data[i+2]=Math.round(startColor.b+(endColor.b-startColor.b)*intensity)}}drawSegmentedData(data,min,rangeY,width,height,accumulator){const segmentSize=EYE_CONFIG.SEGMENT_SIZE;const segmentCount=Math.ceil(data.length/segmentSize);const pointSpacing=width/(segmentSize-1);for(let segment=0;segment<segmentCount;segment++){const points=[];for(let i=0;i<segmentSize;i++){const dataIndex=segment*segmentSize+i;if(dataIndex>=data.length)continue;const value=data[dataIndex];if(void 0!==value){const x=Math.round(i*pointSpacing);const y=Math.round((value-min)/rangeY*height);points.push({x,y})}}if(points.length>1)for(let i=0;i<points.length-1;i++)this.drawLine(points[i].x,points[i].y,points[i+1].x,points[i+1].y,width,height,accumulator)}}drawLine(x0,y0,x1,y1,width,height,accumulator){const dx=Math.abs(x1-x0);const dy=Math.abs(y1-y0);const sx=x0<x1?1:-1;const sy=y0<y1?1:-1;let x=x0;let y=y0;let err=dx-dy;while(true){if(x>=0&&x<width&&y>=0&&y<height){const index=y*width+x;if(accumulator[index]<255)accumulator[index]++}if(x===x1&&y===y1)break;const e2=2*err;if(e2>-dy){err-=dy;x+=sx}if(e2<dx){err+=dx;y+=sy}}}}export{ColorInterpolator,Dial,Fluorescence,Gauge,enums_GraphicType as GraphicType,cartesian_Heatmap as Heatmap,HeatmapCanvas,HeatmapWebGL,IQ,IQEye,enums_OrientationType as OrientationType,Radar,enums_RendererType as RendererType,cartesian_Series as Series,SeriesCanvas,SeriesWebGL,color2intensity,createHeatmap,createSeries,hexToRGBA,rgbToHex};
|
package/package.json
CHANGED
|
@@ -1,13 +1,39 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
clear(): void;
|
|
1
|
+
import type { InitProps, Range, SeriesConfig } from '../../types';
|
|
2
|
+
import SeriesCanvas from './SeriesCanvas';
|
|
3
|
+
/** Series 统一接口 */
|
|
4
|
+
export interface ISeries {
|
|
5
|
+
render(e: SeriesConfig): void;
|
|
7
6
|
setRange(range: Range): void;
|
|
8
7
|
setIntervel(interval: number): void;
|
|
9
8
|
setSeries(e: SeriesConfig): void;
|
|
10
|
-
|
|
9
|
+
clear(): void;
|
|
10
|
+
resize(): void;
|
|
11
|
+
dispose(): void;
|
|
11
12
|
draw(): void;
|
|
13
|
+
updateProps(e: Record<string, unknown>): void;
|
|
14
|
+
}
|
|
15
|
+
/** Series 构造函数类型 */
|
|
16
|
+
interface SeriesConstructor {
|
|
17
|
+
new (props: InitProps): ISeries;
|
|
18
|
+
(props: InitProps): ISeries;
|
|
12
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* 创建 Series 实例
|
|
22
|
+
* 根据 renderer 参数自动选择 Canvas 2D 或 WebGL 实现
|
|
23
|
+
*/
|
|
24
|
+
export declare function createSeries(props: InitProps): ISeries;
|
|
25
|
+
/**
|
|
26
|
+
* Series - 通过 renderer 参数选择实现
|
|
27
|
+
* 支持 new Series() 或 Series() 两种调用方式
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* // Canvas 2D 版本(默认)
|
|
31
|
+
* const series = new Series({ id: 'canvas', range });
|
|
32
|
+
*
|
|
33
|
+
* // WebGL 版本
|
|
34
|
+
* const series = new Series({ id: 'canvas', range, renderer: RendererType.WebGL });
|
|
35
|
+
*/
|
|
36
|
+
declare const Series: SeriesConstructor;
|
|
37
|
+
export default Series;
|
|
38
|
+
export { SeriesCanvas };
|
|
13
39
|
//# sourceMappingURL=Series.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Series.d.ts","sourceRoot":"","sources":["../../../src/renderers/cartesian/Series.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Series.d.ts","sourceRoot":"","sources":["../../../src/renderers/cartesian/Series.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGlE,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAE1C,kBAAkB;AAClB,MAAM,WAAW,OAAO;IACtB,MAAM,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,SAAS,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;IAChB,IAAI,IAAI,IAAI,CAAC;IACb,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC/C;AAED,oBAAoB;AACpB,UAAU,iBAAiB;IACzB,KAAK,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;IAChC,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAQtD;AAED;;;;;;;;;;GAUG;AACH,QAAA,MAAM,MAAM,EAAE,iBAEQ,CAAC;AAEvB,eAAe,MAAM,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import Engine from '../../core/Engine';
|
|
2
|
+
import type { InitProps, Range, SeriesConfig, SeriesState } from '../../types';
|
|
3
|
+
export default class SeriesCanvas extends Engine<SeriesState> {
|
|
4
|
+
init(props: InitProps): void;
|
|
5
|
+
updateProps(e: Partial<SeriesState>): void;
|
|
6
|
+
clear(): void;
|
|
7
|
+
setRange(range: Range): void;
|
|
8
|
+
setIntervel(interval: number): void;
|
|
9
|
+
setSeries(e: SeriesConfig): void;
|
|
10
|
+
render(e: SeriesConfig): void;
|
|
11
|
+
draw(): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=SeriesCanvas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SeriesCanvas.d.ts","sourceRoot":"","sources":["../../../src/renderers/cartesian/SeriesCanvas.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/E,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,MAAM,CAAC,WAAW,CAAC;IAC3D,IAAI,CAAC,KAAK,EAAE,SAAS;IAqBrB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC;IAYnC,KAAK;IAcL,QAAQ,CAAC,KAAK,EAAE,KAAK;IAOrB,WAAW,CAAC,QAAQ,EAAE,MAAM;IAK5B,SAAS,CAAC,CAAC,EAAE,YAAY;IAoBzB,MAAM,CAAC,CAAC,EAAE,YAAY;IAKtB,IAAI;CAuQL"}
|
|
@@ -2,5 +2,6 @@ export { default as Fluorescence } from './Fluorescence';
|
|
|
2
2
|
export { default as Gauge } from './Gauge';
|
|
3
3
|
export type { IHeatmap } from './Heatmap';
|
|
4
4
|
export { createHeatmap, default as Heatmap, HeatmapCanvas } from './Heatmap';
|
|
5
|
-
export {
|
|
5
|
+
export type { ISeries } from './Series';
|
|
6
|
+
export { createSeries, default as Series, SeriesCanvas } from './Series';
|
|
6
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/renderers/cartesian/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,SAAS,CAAC;AAC3C,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,OAAO,IAAI,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/renderers/cartesian/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACzD,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,SAAS,CAAC;AAC3C,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,OAAO,IAAI,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC7E,YAAY,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,OAAO,IAAI,MAAM,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HeatmapWebGL.d.ts","sourceRoot":"","sources":["../../../src/renderers/webgl/HeatmapWebGL.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,WAAW,EAAE,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,sBAAsB;AACtB,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IACjB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAC9B;
|
|
1
|
+
{"version":3,"file":"HeatmapWebGL.d.ts","sourceRoot":"","sources":["../../../src/renderers/webgl/HeatmapWebGL.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,WAAW,EAAE,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEhE,sBAAsB;AACtB,MAAM,WAAW,iBAAkB,SAAQ,cAAc;IACvD,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IACjB,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,EAAE,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAC9B;AAwDD,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,WAAW,CAAC,iBAAiB,CAAC;IACtE,IAAI,CAAC,KAAK,EAAE,SAAS;IAgDrB,eAAe;IACf,OAAO,CAAC,kBAAkB;IAiC1B,aAAa;IACb,OAAO,CAAC,iBAAiB;IAwDzB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAgBzC,QAAQ,CAAC,KAAK,EAAE,KAAK;IAMrB,KAAK;IAOL,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE;IAQvB,IAAI;IAwCJ,MAAM;IAIN,OAAO;CAUR"}
|