@rfkit/renderer 0.1.2 → 0.1.3
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 +1 -1
- package/index.d.ts.map +1 -1
- package/index.js +2 -76
- package/package.json +1 -1
- package/renderers/cartesian/Fluorescence.d.ts.map +1 -1
- package/renderers/cartesian/Heatmap.d.ts +1 -0
- package/renderers/cartesian/Heatmap.d.ts.map +1 -1
- package/renderers/cartesian/Series.d.ts +1 -6
- package/renderers/cartesian/Series.d.ts.map +1 -1
- package/renderers/circular/Dial.d.ts.map +1 -1
- package/renderers/webgl/HeatmapWebGL.d.ts.map +1 -1
- package/renderers/webgl/index.d.ts +0 -2
- package/renderers/webgl/index.d.ts.map +1 -1
- package/types/common.d.ts +11 -7
- package/types/common.d.ts.map +1 -1
- package/utils/index.d.ts +1 -0
- package/utils/index.d.ts.map +1 -1
- package/utils/webgl.d.ts +6 -0
- package/utils/webgl.d.ts.map +1 -0
- package/renderers/webgl/SeriesWebGL.d.ts +0 -56
- package/renderers/webgl/SeriesWebGL.d.ts.map +0 -1
package/index.d.ts
CHANGED
|
@@ -4,6 +4,6 @@ export type { IHeatmap, ISeries } from './renderers/cartesian';
|
|
|
4
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
|
-
export { HeatmapWebGL
|
|
7
|
+
export { HeatmapWebGL } from './renderers/webgl';
|
|
8
8
|
export { type AxisYRange, type CircularData, type GaugeData, GraphicType, type IQData, OrientationType, RendererType, type SeriesConfig, type StateProps } from './types';
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
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,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,
|
|
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,MAAM,mBAAmB,CAAC;AACjD,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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const colorCache=new Map;function hexToRGBA(hexColor,alpha){const hexRegex=/^#([A-Fa-f0-9]{3}){1,2}([A-Fa-f0-9]{2})?$/;if(!hexRegex.test(hexColor))throw new Error("Invalid hex color format");const hex=hexColor.replace("#","");let r;let g;let b;let a;if(3===hex.length){r=Number.parseInt(hex[0]+hex[0],16);g=Number.parseInt(hex[1]+hex[1],16);b=Number.parseInt(hex[2]+hex[2],16);a=255}else if(6===hex.length){r=Number.parseInt(hex.substring(0,2),16);g=Number.parseInt(hex.substring(2,4),16);b=Number.parseInt(hex.substring(4,6),16);a=255}else if(8===hex.length){r=Number.parseInt(hex.substring(0,2),16);g=Number.parseInt(hex.substring(2,4),16);b=Number.parseInt(hex.substring(4,6),16);a=Number.parseInt(hex.substring(6,8),16)}else throw new Error("Invalid hex color length");if("number"==typeof alpha)a=Math.round(255*Math.max(0,Math.min(1,alpha)));return{r,g,b,a}}function rgbToHex(r,g,b,a=255){const toHex=channel=>channel.toString(16).padStart(2,"0");const hex=`#${toHex(r)}${toHex(g)}${toHex(b)}`;return a<255?`${hex}${toHex(a)}`:hex}function parseColor(color){if("string"==typeof color){const cached=colorCache.get(color);if(cached)return cached;const result=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(color);const parsed=result?{r:parseInt(result[1],16),g:parseInt(result[2],16),b:parseInt(result[3],16),a:result[4]?parseInt(result[4],16):255}:{r:0,g:0,b:0,a:255};colorCache.set(color,parsed);return parsed}return{r:color.r,g:color.g,b:color.b,a:color.a??255}}function color2intensity(color,length=100){const colorArray=[];for(let i=0;i<=length;i++){const alphaHex=Math.round(i/length*255);const alphaHexString=alphaHex.toString(16).padStart(2,"0").toUpperCase();const colorWithOpacity=`${color}${alphaHexString}`;colorArray.push(colorWithOpacity)}return colorArray}function clearColorCache(){colorCache.clear()}class ColorInterpolator{colorsPresetList=[];range=[0,0,0];static transparent={r:0,g:0,b:0,a:0};constructor(colors,rangeMin,rangeMax,stepSize=.1){this.setColors(colors,rangeMin,rangeMax,stepSize)}setColors(colors,rangeMin,rangeMax,stepSize){this.colorsPresetList=[];const steps=Math.max(1,Math.floor((rangeMax-rangeMin)/stepSize));const rangeDiff=rangeMax-rangeMin;this.range=[rangeMin,rangeMax,rangeDiff];const parsedColors=colors.map(parseColor);for(let i=0;i<=steps;i++){const value=rangeMin+i*stepSize;const position=(value-rangeMin)/rangeDiff;this.colorsPresetList.push(this.interpolateColor(parsedColors,position))}}interpolateColor(colors,position){const index=Math.floor(position*(colors.length-1));const ratio=position*(colors.length-1)-index;const startColor=colors[index];const endColor=colors[index+1]||colors[index];const rgba={r:Math.round(startColor.r+ratio*(endColor.r-startColor.r)),g:Math.round(startColor.g+ratio*(endColor.g-startColor.g)),b:Math.round(startColor.b+ratio*(endColor.b-startColor.b)),a:Math.round(startColor.a+ratio*(endColor.a-startColor.a))};return{...rgba,hax:rgbToHex(rgba.r,rgba.g,rgba.b,rgba.a)}}getColor(value){if(!Number.isFinite(value))return ColorInterpolator.transparent;const[rangeMin,,rangeDiff]=this.range;const position=(value-rangeMin)/rangeDiff;if(position<=0)return this.colorsPresetList[0];if(position>=1)return this.colorsPresetList[this.colorsPresetList.length-1];const index=Math.min(Math.floor(position*this.colorsPresetList.length),this.colorsPresetList.length-1);return this.colorsPresetList[index]}}class Engine{state;constructor(props){this.state={id:props.id,container:void 0,canvas:null,ctx:null,range:props.range??[-20,100]};this.init(props)}updateProps(e){this.state={...this.state,...e}}init(_props){const{id}=this.state;const container=document.getElementById(id);const canvas=document.createElement("canvas");const ctx=canvas.getContext?.("2d");canvas.style.transform="scaleY(-1)";if(ctx){ctx.imageSmoothingEnabled=false;ctx.lineJoin="miter";ctx.lineCap="butt";ctx.textBaseline="middle"}if(ctx)this.updateProps({container:container??void 0,canvas,ctx});container?.appendChild(canvas);this.resize(false)}clearRect(){const{ctx,canvas}=this.state;ctx.clearRect(0,0,canvas.width,canvas.height)}resize(draw=true){const{canvas,container}=this.state;const{clientWidth,clientHeight}=container;if(!clientWidth||!clientHeight)return;canvas.width=clientWidth;canvas.height=clientHeight;if(draw)setTimeout(()=>{this.draw()})}draw(){}dispose(){const{canvas,container}=this.state;container?.removeChild(canvas)}}const BLOCK_RENDER_MODE=true;class Fluorescence extends Engine{init(props){super.init(props);const{colors,display}=props;this.updateProps({colors,data:[],display});this.resize()}updateProps(e){super.updateProps(e)}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:[]})}dispose(){this.intensityMatrixCache=null;this.gridCentersCache=null;this.weightLookupCache=null;this.colorLookupCache=null;this.colorCache.clear();this.lastRenderParams=null;this.blockPositionsCache=null;this.lastBlockRenderParams=null}drawBlocks(){const{imageData,data,canvas,ctx,colors=["#000080","#0000FF","#00FFFF","#00FF00","#FFFF00","#FF0000"],range=[-20,100],fluorescenceMaxCount=1}=this.state;if(!data||0===data.length||!imageData)return;const{width,height}=canvas;const[rangeMin,rangeMax]=range;const rangeSpan=rangeMax-rangeMin;if(rangeSpan<=0)return;const dataLength=data.length;const currentParams={dataLength,width,height,rangeMin,rangeMax};const paramsChanged=!this.lastBlockRenderParams||Object.keys(currentParams).some(key=>this.lastBlockRenderParams?.[key]!==currentParams[key]);if(paramsChanged||!this.blockPositionsCache||this.blockPositionsCache.length!==dataLength){this.blockPositionsCache=new Array(dataLength);const blockWidth=Math.max(1,Math.floor(width/dataLength));for(let i=0;i<dataLength;i++){const startX=Math.floor(i*width/dataLength);const endX=Math.min(width-1,startX+blockWidth-1);this.blockPositionsCache[i]={startX,endX,width:endX-startX+1}}}this.lastBlockRenderParams=currentParams;const pixelData=imageData.data;pixelData.fill(0);const invRangeSpan=1/rangeSpan;const heightMinus1=height-1;for(let dataIndex=0;dataIndex<dataLength;dataIndex++){const bin=data[dataIndex];if(!bin||0===bin.size)continue;const blockPos=this.blockPositionsCache[dataIndex];const{startX:blockStartX,endX:blockEndX}=blockPos;for(const[yValue,count]of bin.entries()){if(yValue<rangeMin||yValue>rangeMax||count<=0)continue;const normalizedY=(yValue-rangeMin)*invRangeSpan;const centerY=normalizedY*heightMinus1;const yValueCount=bin.size;const blockHeight=Math.max(1,Math.floor(height/Math.max(2*yValueCount,20)));const blockStartY=Math.max(0,Math.floor(centerY-blockHeight/2));const blockEndY=Math.min(heightMinus1,blockStartY+blockHeight-1);const intensity=Math.min(count/fluorescenceMaxCount,1);const alpha=Math.round(255*intensity);const blockColor=this.interpolateColor(colors,intensity);const{r:colorR,g:colorG,b:colorB}=blockColor;for(let py=blockStartY;py<=blockEndY;py++){const rowIndex=py*width;for(let px=blockStartX;px<=blockEndX;px++){const pixelIndex=(rowIndex+px)*4;pixelData[pixelIndex]=colorR;pixelData[pixelIndex+1]=colorG;pixelData[pixelIndex+2]=colorB;pixelData[pixelIndex+3]=alpha}}}}ctx.putImageData(imageData,0,0)}resize(){super.resize();this.clearImageData()}setRange(range){if(!range)return;this.updateProps({range});this.draw()}render(data){if(data?.fluorescenceData?.length>=0){this.state.data=data.fluorescenceData;this.state.fluorescenceMaxCount=data.fluorescenceMaxCount;this.draw()}}interpolateColor(colors,ratio){if(!colors||0===colors.length)return{r:255,g:255,b:255,a:255};ratio=Math.max(0,Math.min(1,ratio));const getColorRgb=color=>{if("string"==typeof color)return this.hexToRgb(color);return{r:color.r,g:color.g,b:color.b}};if(1===colors.length){const color=getColorRgb(colors[0]);return{...color,a:255}}if(0===ratio){const color=getColorRgb(colors[0]);return{...color,a:255}}if(1===ratio){const color=getColorRgb(colors[colors.length-1]);return{...color,a:255}}const scaledRatio=ratio*(colors.length-1);const index=Math.floor(scaledRatio);const localRatio=scaledRatio-index;const safeIndex=Math.min(index,colors.length-2);const color1=getColorRgb(colors[safeIndex]);const color2=getColorRgb(colors[safeIndex+1]);return{r:Math.round(color1.r+(color2.r-color1.r)*localRatio),g:Math.round(color1.g+(color2.g-color1.g)*localRatio),b:Math.round(color1.b+(color2.b-color1.b)*localRatio),a:255}}colorCache=new Map;hexToRgb(hex){const cached=this.colorCache.get(hex);if(cached)return cached;const parsed=parseColor(hex);const color={r:parsed.r,g:parsed.g,b:parsed.b};this.colorCache.set(hex,color);return color}lastRenderParams=null;intensityMatrixCache=null;gridCentersCache=null;weightLookupCache=null;colorLookupCache=null;blockPositionsCache=null;lastBlockRenderParams=null;draw(){const{imageData,data,canvas,ctx,colors=["#000080","#0000FF","#00FFFF","#00FF00","#FFFF00","#FF0000"],range=[-20,100],fluorescenceMaxCount=1,display}=this.state;if(!display)return;if(!data||0===data.length||!imageData)return;if(BLOCK_RENDER_MODE){this.drawBlocks();return}const{width,height}=canvas;const[rangeMin,rangeMax]=range;const rangeSpan=rangeMax-rangeMin;if(rangeSpan<=0)return;const currentParams={dataLength:data.length,rangeMin,rangeMax,width,height,maxCount:fluorescenceMaxCount};const paramsChanged=!this.lastRenderParams||Object.keys(currentParams).some(key=>this.lastRenderParams?.[key]!==currentParams[key]);if(!paramsChanged)return;const needRecalcGridCenters=!this.lastRenderParams||this.lastRenderParams.dataLength!==currentParams.dataLength||this.lastRenderParams.width!==currentParams.width;const needRecalcWeightLookup=!this.lastRenderParams||this.lastRenderParams.height!==currentParams.height;const needRecalcColorLookup=!this.colorLookupCache;this.lastRenderParams=currentParams;const pixelData=imageData.data;pixelData.fill(0);const interpolationRadius=Math.max(2,Math.floor(height/50));const radiusSquared=interpolationRadius*interpolationRadius;const dataLength=data.length;const matrixSize=width*height;if(this.intensityMatrixCache&&this.intensityMatrixCache.length===matrixSize)this.intensityMatrixCache.fill(0);else this.intensityMatrixCache=new Float32Array(matrixSize);const intensityMatrix=this.intensityMatrixCache;if(needRecalcGridCenters||!this.gridCentersCache||this.gridCentersCache.length!==dataLength){this.gridCentersCache=new Float32Array(dataLength);const cellWidth=width/dataLength;for(let i=0;i<dataLength;i++){const startX=Math.floor(cellWidth*i);const endX=Math.ceil(cellWidth*(i+1));this.gridCentersCache[i]=(startX+endX)/2}}const gridCenters=this.gridCentersCache;const maxDistance=interpolationRadius;const lookupSize=Math.ceil(10*maxDistance)+1;if(needRecalcWeightLookup||!this.weightLookupCache||this.weightLookupCache.length!==lookupSize){this.weightLookupCache=new Float32Array(lookupSize);for(let i=0;i<=10*maxDistance;i++){const distance=i/10;this.weightLookupCache[i]=Math.exp(-(distance*distance)/(2*radiusSquared))}}const weightLookup=this.weightLookupCache;let maxIntensity=0;for(let dataIndex=0;dataIndex<dataLength;dataIndex++){const bin=data[dataIndex];if(!bin||0===bin.size)continue;const centerX=gridCenters[dataIndex];for(const[yValue,count]of bin.entries()){if(yValue<rangeMin||yValue>rangeMax||count<=0)continue;const normalizedY=(yValue-rangeMin)/rangeSpan;const centerY=normalizedY*(height-1);const intensity=Math.min(count/fluorescenceMaxCount,1);const expandStartX=Math.max(0,Math.floor(centerX-interpolationRadius));const expandEndX=Math.min(width-1,Math.ceil(centerX+interpolationRadius));const startY=Math.max(0,Math.floor(centerY-interpolationRadius));const endY=Math.min(height-1,Math.ceil(centerY+interpolationRadius));for(let py=startY;py<=endY;py++){const dy=py-centerY;const dySquared=dy*dy;const rowIndex=py*width;for(let px=expandStartX;px<=expandEndX;px++){const dx=px-centerX;const distanceSquared=dx*dx+dySquared;if(distanceSquared>radiusSquared)continue;const distance=Math.sqrt(distanceSquared);const lookupIndex=Math.floor(10*distance);const weight=lookupIndex<weightLookup.length?weightLookup[lookupIndex]:0;const matrixIndex=rowIndex+px;const newIntensity=intensityMatrix[matrixIndex]+intensity*weight;intensityMatrix[matrixIndex]=newIntensity;if(newIntensity>maxIntensity)maxIntensity=newIntensity}}}}const intensityThreshold=.001;const invMaxIntensity=maxIntensity>0?1/maxIntensity:0;const colorSteps=256;if(needRecalcColorLookup||!this.colorLookupCache||this.colorLookupCache.length!==colorSteps){this.colorLookupCache=new Array(colorSteps);for(let i=0;i<colorSteps;i++){const ratio=i/(colorSteps-1);this.colorLookupCache[i]=this.interpolateColor(colors,ratio)}}const colorLookup=this.colorLookupCache;for(let i=0;i<intensityMatrix.length;i++){const rawIntensity=intensityMatrix[i];if(rawIntensity<=intensityThreshold)continue;const intensity=rawIntensity*invMaxIntensity;const colorIndex=Math.floor(intensity*(colorSteps-1));const color=colorLookup[colorIndex];const pixelIndex=4*i;pixelData[pixelIndex]=color.r;pixelData[pixelIndex+1]=color.g;pixelData[pixelIndex+2]=color.b;pixelData[pixelIndex+3]=Math.round(255*intensity)}ctx.putImageData(imageData,0,0)}}const DEFAULTS={COLOR:"#000000",THICKNESS:1,FILL_STYLE:"#ffffffB0",FILL_STYLE_PRIMARY:"#1890ff",FILL_STYLE_TRANSPARENT_BASE:"#ffffff10",LINE_COLOR:"#00ff00",POINT_COLOR:"#ff0000"};var enums_OrientationType=/*#__PURE__*/function(OrientationType){OrientationType["Horizontal"]="horizontal";OrientationType["Vertical"]="vertical";return OrientationType}({});var enums_GraphicType=/*#__PURE__*/function(GraphicType){GraphicType["Circle"]="circle";GraphicType["Rect"]="rect";GraphicType["Line"]="line";GraphicType["Stepline"]="stepline";GraphicType["Bar"]="bar";GraphicType["Area"]="area";return GraphicType}({});var enums_RendererType=/*#__PURE__*/function(RendererType){RendererType["Canvas"]="canvas";RendererType["WebGL"]="webgl";return RendererType}({});function fillImageData(canvasWidth,canvasHeight,data,imageData,getColor){if(!data)return;const numRows=data.length;const cellHeight=canvasHeight/numRows;let cellWidth=0;for(let r=0;r<numRows;r++){const rowData=data[r];const numCols=rowData.length;if(0===numCols)continue;if(0===cellWidth)cellWidth=canvasWidth/numCols;const startRow=Math.floor(cellHeight*r);const endRow=Math.ceil(cellHeight*(r+1));for(let c=0;c<numCols;c++){const value=rowData[c];const startCol=Math.floor(cellWidth*c);const endCol=Math.ceil(cellWidth*(c+1));const color=getColor(value);for(let y=startRow;y<endRow;y++){const rowIndex=y*canvasWidth;for(let x=startCol;x<endCol;x++){const index=(rowIndex+x)*4;imageData[index]=color.r;imageData[index+1]=color.g;imageData[index+2]=color.b;imageData[index+3]=color.a}}}}}function getMinMax(numbers){if(!Array.isArray(numbers)||0===numbers.length)throw new Error("Input must be a non-empty array.");let min=numbers[0];let max=numbers[0];for(let i=1;i<numbers.length;i++)if(numbers[i]<min)min=numbers[i];else if(numbers[i]>max)max=numbers[i];return[min,max]}function isNumberAlias(n){return"number"==typeof n&&Number.isFinite(n)}function convertToF64(odata){const flattened=odata.flatMap(row=>{if(0===row.length)return Array(odata[0].length).fill(Number.NaN);return row});return new Float64Array(flattened)}class Gauge extends Engine{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 baseWidth=6;this.updateProps({fillStyle,fillStylePrimary,fillStyleTransparentBase,baseWidth,padding:props.padding??0,step:props.ticksStep??10,lineWidth:1,data:{value:0,limit:0}})}clear(){this.clearRect();const{ctx,BGCanvas}=this.state;if(BGCanvas)ctx.drawImage(BGCanvas,0,0)}resize(){super.resize();if(this.state.lineWidth)this.drawBackground()}render(data){this.state.data={...this.state.data,...data};this.draw()}draw(){const{data:{value},range:[min,max],canvas,ctx,baseWidth,padding,BGCanvas,fillStylePrimary}=this.state;this.clearRect();if(BGCanvas)ctx.drawImage(BGCanvas,0,0);const width=3*baseWidth;const height=canvas.height-2*padding;const x=(canvas.width-width)/2;const renderHeight=(value-min)/(max-min)*height;const y=height-renderHeight+padding;ctx.fillStyle=fillStylePrimary;ctx.fillRect(x,y,width,renderHeight);this.drawLimit()}drawLimit(){const{data:{limit},range:[min,max],canvas,ctx,baseWidth,padding,lineWidth,fillStylePrimary}=this.state;if(!isNumberAlias(limit))return;const width=3*baseWidth;const height=canvas.height-2*padding;const x=(canvas.width-width)/2;const y=height*(max-limit)/(max-min)+padding;const limitTagHeight=9;const triangleWidth=9;const rectangleWidth=30;ctx.beginPath();ctx.moveTo(x+width,y);ctx.lineTo(x+width+triangleWidth,y-limitTagHeight);ctx.lineTo(x+width+triangleWidth+rectangleWidth,y-limitTagHeight);ctx.lineTo(x+width+triangleWidth+rectangleWidth,y+limitTagHeight);ctx.lineTo(x+width+triangleWidth,y+limitTagHeight);ctx.lineTo(x+width,y);ctx.lineTo(x,y);ctx.lineWidth=lineWidth;ctx.strokeStyle=fillStylePrimary;ctx.stroke();ctx.fillStyle=fillStylePrimary;ctx.font="12px Arial";ctx.textAlign="center";ctx.textBaseline="middle";ctx.fillText(limit.toString(),x+width+triangleWidth+rectangleWidth/2,y+1)}drawBackground(){const{canvas,baseWidth,padding,lineWidth,step,range:[min,max],fillStyle,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 width=3*baseWidth;const height=canvas.height-2*padding;const x=(canvas.width-width)/2;const y=padding;const tagNun=11;const markedAngles=Array.from({length:tagNun},(_,i)=>min+Math.round(i*(max-min)/(tagNun-1)/step)*step);BGCtx.fillStyle=fillStyleTransparentBase;BGCtx.fillRect(x,y,width,height);for(let i=min;i<=max;i+=step){const isMarked=markedAngles.includes(i);const tagY=height*(max-i)/(max-min)+padding;BGCtx.beginPath();BGCtx.moveTo(x-(isMarked?baseWidth:baseWidth/2),tagY);BGCtx.lineTo(x,tagY);BGCtx.strokeStyle=fillStyle;BGCtx.lineWidth=isMarked?lineWidth:lineWidth/2;BGCtx.stroke();if(isMarked){BGCtx.fillStyle=fillStyle;BGCtx.font="12px Arial";BGCtx.textAlign="right";BGCtx.textBaseline="middle";BGCtx.fillText(i.toString(),x-1.2*baseWidth,tagY)}}this.state.BGCanvas=BGCanvas}}class WebGLEngine{state;constructor(props){this.state={id:props.id,container:void 0,canvas:null,gl:null,range:props.range??[-20,100]};this.init(props)}updateProps(e){this.state={...this.state,...e}}init(_props){const{id}=this.state;const container=document.getElementById(id);const canvas=document.createElement("canvas");const gl=canvas.getContext("webgl2",{alpha:true,antialias:false,premultipliedAlpha:false,preserveDrawingBuffer:false});if(!gl){console.error("WebGL 2.0 not supported");return}canvas.style.transform="scaleY(-1)";this.updateProps({container:container??void 0,canvas,gl});container?.appendChild(canvas);this.resize(false)}compileShader(type,source){const{gl}=this.state;const shader=gl.createShader(type);if(!shader)return null;gl.shaderSource(shader,source);gl.compileShader(shader);if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){console.error("Shader compile error:",gl.getShaderInfoLog(shader));gl.deleteShader(shader);return null}return shader}createProgram(shaderSource){const{gl}=this.state;const vertexShader=this.compileShader(gl.VERTEX_SHADER,shaderSource.vertex);const fragmentShader=this.compileShader(gl.FRAGMENT_SHADER,shaderSource.fragment);if(!vertexShader||!fragmentShader)return null;const program=gl.createProgram();if(!program)return null;gl.attachShader(program,vertexShader);gl.attachShader(program,fragmentShader);gl.linkProgram(program);if(!gl.getProgramParameter(program,gl.LINK_STATUS)){console.error("Program link error:",gl.getProgramInfoLog(program));gl.deleteProgram(program);return null}gl.deleteShader(vertexShader);gl.deleteShader(fragmentShader);return program}createTexture(){const{gl}=this.state;const texture=gl.createTexture();if(!texture)return null;gl.bindTexture(gl.TEXTURE_2D,texture);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);return texture}createQuadBuffer(){const{gl}=this.state;const buffer=gl.createBuffer();if(!buffer)return null;gl.bindBuffer(gl.ARRAY_BUFFER,buffer);const vertices=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]);gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);return buffer}clearRect(){const{gl}=this.state;gl.clearColor(0,0,0,0);gl.clear(gl.COLOR_BUFFER_BIT)}resize(draw=true){const{canvas,container,gl}=this.state;if(!container)return;const{clientWidth,clientHeight}=container;if(!clientWidth||!clientHeight)return;canvas.width=clientWidth;canvas.height=clientHeight;gl.viewport(0,0,clientWidth,clientHeight);if(draw)setTimeout(()=>{this.draw()})}draw(){}dispose(){const{gl,canvas}=this.state;if(gl){const loseContext=gl.getExtension("WEBGL_lose_context");if(loseContext)loseContext.loseContext()}canvas?.remove()}}const VERTEX_SHADER=`#version 300 es
|
|
1
|
+
const colorCache=new Map;function hexToRGBA(hexColor,alpha){const hexRegex=/^#([A-Fa-f0-9]{3}){1,2}([A-Fa-f0-9]{2})?$/;if(!hexRegex.test(hexColor))throw new Error("Invalid hex color format");const hex=hexColor.replace("#","");let r;let g;let b;let a;if(3===hex.length){r=Number.parseInt(hex[0]+hex[0],16);g=Number.parseInt(hex[1]+hex[1],16);b=Number.parseInt(hex[2]+hex[2],16);a=255}else if(6===hex.length){r=Number.parseInt(hex.substring(0,2),16);g=Number.parseInt(hex.substring(2,4),16);b=Number.parseInt(hex.substring(4,6),16);a=255}else if(8===hex.length){r=Number.parseInt(hex.substring(0,2),16);g=Number.parseInt(hex.substring(2,4),16);b=Number.parseInt(hex.substring(4,6),16);a=Number.parseInt(hex.substring(6,8),16)}else throw new Error("Invalid hex color length");if("number"==typeof alpha)a=Math.round(255*Math.max(0,Math.min(1,alpha)));return{r,g,b,a}}function rgbToHex(r,g,b,a=255){const toHex=channel=>channel.toString(16).padStart(2,"0");const hex=`#${toHex(r)}${toHex(g)}${toHex(b)}`;return a<255?`${hex}${toHex(a)}`:hex}function parseColor(color){if("string"==typeof color){const cached=colorCache.get(color);if(cached)return cached;const result=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(color);const parsed=result?{r:parseInt(result[1],16),g:parseInt(result[2],16),b:parseInt(result[3],16),a:result[4]?parseInt(result[4],16):255}:{r:0,g:0,b:0,a:255};colorCache.set(color,parsed);return parsed}return{r:color.r,g:color.g,b:color.b,a:color.a??255}}function color2intensity(color,length=100){const colorArray=[];for(let i=0;i<=length;i++){const alphaHex=Math.round(i/length*255);const alphaHexString=alphaHex.toString(16).padStart(2,"0").toUpperCase();const colorWithOpacity=`${color}${alphaHexString}`;colorArray.push(colorWithOpacity)}return colorArray}function clearColorCache(){colorCache.clear()}class ColorInterpolator{colorsPresetList=[];range=[0,0,0];static transparent={r:0,g:0,b:0,a:0};constructor(colors,rangeMin,rangeMax,stepSize=.1){this.setColors(colors,rangeMin,rangeMax,stepSize)}setColors(colors,rangeMin,rangeMax,stepSize){this.colorsPresetList=[];const steps=Math.max(1,Math.floor((rangeMax-rangeMin)/stepSize));const rangeDiff=rangeMax-rangeMin;this.range=[rangeMin,rangeMax,rangeDiff];const parsedColors=colors.map(parseColor);for(let i=0;i<=steps;i++){const value=rangeMin+i*stepSize;const position=(value-rangeMin)/rangeDiff;this.colorsPresetList.push(this.interpolateColor(parsedColors,position))}}interpolateColor(colors,position){const index=Math.floor(position*(colors.length-1));const ratio=position*(colors.length-1)-index;const startColor=colors[index];const endColor=colors[index+1]||colors[index];const rgba={r:Math.round(startColor.r+ratio*(endColor.r-startColor.r)),g:Math.round(startColor.g+ratio*(endColor.g-startColor.g)),b:Math.round(startColor.b+ratio*(endColor.b-startColor.b)),a:Math.round(startColor.a+ratio*(endColor.a-startColor.a))};return{...rgba,hax:rgbToHex(rgba.r,rgba.g,rgba.b,rgba.a)}}getColor(value){if(!Number.isFinite(value))return ColorInterpolator.transparent;const[rangeMin,,rangeDiff]=this.range;const position=(value-rangeMin)/rangeDiff;if(position<=0)return this.colorsPresetList[0];if(position>=1)return this.colorsPresetList[this.colorsPresetList.length-1];const index=Math.min(Math.floor(position*this.colorsPresetList.length),this.colorsPresetList.length-1);return this.colorsPresetList[index]}}class Engine{state;constructor(props){this.state={id:props.id,container:void 0,canvas:null,ctx:null,range:props.range??[-20,100]};this.init(props)}updateProps(e){this.state={...this.state,...e}}init(_props){const{id}=this.state;const container=document.getElementById(id);const canvas=document.createElement("canvas");const ctx=canvas.getContext?.("2d");canvas.style.transform="scaleY(-1)";if(ctx){ctx.imageSmoothingEnabled=false;ctx.lineJoin="miter";ctx.lineCap="butt";ctx.textBaseline="middle"}if(ctx)this.updateProps({container:container??void 0,canvas,ctx});container?.appendChild(canvas);this.resize(false)}clearRect(){const{ctx,canvas}=this.state;ctx.clearRect(0,0,canvas.width,canvas.height)}resize(draw=true){const{canvas,container}=this.state;const{clientWidth,clientHeight}=container;if(!clientWidth||!clientHeight)return;canvas.width=clientWidth;canvas.height=clientHeight;if(draw)setTimeout(()=>{this.draw()})}draw(){}dispose(){const{canvas,container}=this.state;container?.removeChild(canvas)}}const DEFAULTS={COLOR:"#000000",THICKNESS:1,FILL_STYLE:"#ffffffB0",FILL_STYLE_PRIMARY:"#1890ff",FILL_STYLE_TRANSPARENT_BASE:"#ffffff10",LINE_COLOR:"#00ff00",POINT_COLOR:"#ff0000",DIAL_NORTH_COLOR:"#ff4d4f",DIAL_SOUTH_COLOR:"#1890ff",FLUORESCENCE_COLORS:["#000080","#0000FF","#00FFFF","#00FF00","#FFFF00","#FF0000"],RANGE:[-20,100]};var enums_OrientationType=/*#__PURE__*/function(OrientationType){OrientationType["Horizontal"]="horizontal";OrientationType["Vertical"]="vertical";return OrientationType}({});var enums_GraphicType=/*#__PURE__*/function(GraphicType){GraphicType["Circle"]="circle";GraphicType["Rect"]="rect";GraphicType["Line"]="line";GraphicType["Stepline"]="stepline";GraphicType["Bar"]="bar";GraphicType["Area"]="area";return GraphicType}({});var enums_RendererType=/*#__PURE__*/function(RendererType){RendererType["Canvas"]="canvas";RendererType["WebGL"]="webgl";return RendererType}({});const BLOCK_RENDER_MODE=true;class Fluorescence extends Engine{init(props){super.init(props);const{colors,display}=props;this.updateProps({colors,data:[],display});this.resize()}updateProps(e){super.updateProps(e)}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:[]})}dispose(){this.intensityMatrixCache=null;this.gridCentersCache=null;this.weightLookupCache=null;this.colorLookupCache=null;this.colorCache.clear();this.lastRenderParams=null;this.blockPositionsCache=null;this.lastBlockRenderParams=null}drawBlocks(){const{imageData,data,canvas,ctx,colors=DEFAULTS.FLUORESCENCE_COLORS,range=DEFAULTS.RANGE,fluorescenceMaxCount=1}=this.state;if(!data||0===data.length||!imageData)return;const{width,height}=canvas;const[rangeMin,rangeMax]=range;const rangeSpan=rangeMax-rangeMin;if(rangeSpan<=0)return;const dataLength=data.length;const currentParams={dataLength,width,height,rangeMin,rangeMax};const paramsChanged=!this.lastBlockRenderParams||Object.keys(currentParams).some(key=>this.lastBlockRenderParams?.[key]!==currentParams[key]);if(paramsChanged||!this.blockPositionsCache||this.blockPositionsCache.length!==dataLength){this.blockPositionsCache=new Array(dataLength);const blockWidth=Math.max(1,Math.floor(width/dataLength));for(let i=0;i<dataLength;i++){const startX=Math.floor(i*width/dataLength);const endX=Math.min(width-1,startX+blockWidth-1);this.blockPositionsCache[i]={startX,endX,width:endX-startX+1}}}this.lastBlockRenderParams=currentParams;const pixelData=imageData.data;pixelData.fill(0);const invRangeSpan=1/rangeSpan;const heightMinus1=height-1;for(let dataIndex=0;dataIndex<dataLength;dataIndex++){const bin=data[dataIndex];if(!bin||0===bin.size)continue;const blockPos=this.blockPositionsCache[dataIndex];const{startX:blockStartX,endX:blockEndX}=blockPos;for(const[yValue,count]of bin.entries()){if(yValue<rangeMin||yValue>rangeMax||count<=0)continue;const normalizedY=(yValue-rangeMin)*invRangeSpan;const centerY=normalizedY*heightMinus1;const yValueCount=bin.size;const blockHeight=Math.max(1,Math.floor(height/Math.max(2*yValueCount,20)));const blockStartY=Math.max(0,Math.floor(centerY-blockHeight/2));const blockEndY=Math.min(heightMinus1,blockStartY+blockHeight-1);const intensity=Math.min(count/fluorescenceMaxCount,1);const alpha=Math.round(255*intensity);const blockColor=this.interpolateColor(colors,intensity);const{r:colorR,g:colorG,b:colorB}=blockColor;for(let py=blockStartY;py<=blockEndY;py++){const rowIndex=py*width;for(let px=blockStartX;px<=blockEndX;px++){const pixelIndex=(rowIndex+px)*4;pixelData[pixelIndex]=colorR;pixelData[pixelIndex+1]=colorG;pixelData[pixelIndex+2]=colorB;pixelData[pixelIndex+3]=alpha}}}}ctx.putImageData(imageData,0,0)}resize(){super.resize();this.clearImageData()}setRange(range){if(!range)return;this.updateProps({range});this.draw()}render(data){if(data?.fluorescenceData?.length>=0){this.state.data=data.fluorescenceData;this.state.fluorescenceMaxCount=data.fluorescenceMaxCount;this.draw()}}interpolateColor(colors,ratio){if(!colors||0===colors.length)return{r:255,g:255,b:255,a:255};ratio=Math.max(0,Math.min(1,ratio));const getColorRgb=color=>{if("string"==typeof color)return this.hexToRgb(color);return{r:color.r,g:color.g,b:color.b}};if(1===colors.length){const color=getColorRgb(colors[0]);return{...color,a:255}}if(0===ratio){const color=getColorRgb(colors[0]);return{...color,a:255}}if(1===ratio){const color=getColorRgb(colors[colors.length-1]);return{...color,a:255}}const scaledRatio=ratio*(colors.length-1);const index=Math.floor(scaledRatio);const localRatio=scaledRatio-index;const safeIndex=Math.min(index,colors.length-2);const color1=getColorRgb(colors[safeIndex]);const color2=getColorRgb(colors[safeIndex+1]);return{r:Math.round(color1.r+(color2.r-color1.r)*localRatio),g:Math.round(color1.g+(color2.g-color1.g)*localRatio),b:Math.round(color1.b+(color2.b-color1.b)*localRatio),a:255}}colorCache=new Map;hexToRgb(hex){const cached=this.colorCache.get(hex);if(cached)return cached;const parsed=parseColor(hex);const color={r:parsed.r,g:parsed.g,b:parsed.b};this.colorCache.set(hex,color);return color}lastRenderParams=null;intensityMatrixCache=null;gridCentersCache=null;weightLookupCache=null;colorLookupCache=null;blockPositionsCache=null;lastBlockRenderParams=null;draw(){const{imageData,data,canvas,ctx,colors=DEFAULTS.FLUORESCENCE_COLORS,range=DEFAULTS.RANGE,fluorescenceMaxCount=1,display}=this.state;if(!display)return;if(!data||0===data.length||!imageData)return;if(BLOCK_RENDER_MODE){this.drawBlocks();return}const{width,height}=canvas;const[rangeMin,rangeMax]=range;const rangeSpan=rangeMax-rangeMin;if(rangeSpan<=0)return;const currentParams={dataLength:data.length,rangeMin,rangeMax,width,height,maxCount:fluorescenceMaxCount};const paramsChanged=!this.lastRenderParams||Object.keys(currentParams).some(key=>this.lastRenderParams?.[key]!==currentParams[key]);if(!paramsChanged)return;const needRecalcGridCenters=!this.lastRenderParams||this.lastRenderParams.dataLength!==currentParams.dataLength||this.lastRenderParams.width!==currentParams.width;const needRecalcWeightLookup=!this.lastRenderParams||this.lastRenderParams.height!==currentParams.height;const needRecalcColorLookup=!this.colorLookupCache;this.lastRenderParams=currentParams;const pixelData=imageData.data;pixelData.fill(0);const interpolationRadius=Math.max(2,Math.floor(height/50));const radiusSquared=interpolationRadius*interpolationRadius;const dataLength=data.length;const matrixSize=width*height;if(this.intensityMatrixCache&&this.intensityMatrixCache.length===matrixSize)this.intensityMatrixCache.fill(0);else this.intensityMatrixCache=new Float32Array(matrixSize);const intensityMatrix=this.intensityMatrixCache;if(needRecalcGridCenters||!this.gridCentersCache||this.gridCentersCache.length!==dataLength){this.gridCentersCache=new Float32Array(dataLength);const cellWidth=width/dataLength;for(let i=0;i<dataLength;i++){const startX=Math.floor(cellWidth*i);const endX=Math.ceil(cellWidth*(i+1));this.gridCentersCache[i]=(startX+endX)/2}}const gridCenters=this.gridCentersCache;const maxDistance=interpolationRadius;const lookupSize=Math.ceil(10*maxDistance)+1;if(needRecalcWeightLookup||!this.weightLookupCache||this.weightLookupCache.length!==lookupSize){this.weightLookupCache=new Float32Array(lookupSize);for(let i=0;i<=10*maxDistance;i++){const distance=i/10;this.weightLookupCache[i]=Math.exp(-(distance*distance)/(2*radiusSquared))}}const weightLookup=this.weightLookupCache;let maxIntensity=0;for(let dataIndex=0;dataIndex<dataLength;dataIndex++){const bin=data[dataIndex];if(!bin||0===bin.size)continue;const centerX=gridCenters[dataIndex];for(const[yValue,count]of bin.entries()){if(yValue<rangeMin||yValue>rangeMax||count<=0)continue;const normalizedY=(yValue-rangeMin)/rangeSpan;const centerY=normalizedY*(height-1);const intensity=Math.min(count/fluorescenceMaxCount,1);const expandStartX=Math.max(0,Math.floor(centerX-interpolationRadius));const expandEndX=Math.min(width-1,Math.ceil(centerX+interpolationRadius));const startY=Math.max(0,Math.floor(centerY-interpolationRadius));const endY=Math.min(height-1,Math.ceil(centerY+interpolationRadius));for(let py=startY;py<=endY;py++){const dy=py-centerY;const dySquared=dy*dy;const rowIndex=py*width;for(let px=expandStartX;px<=expandEndX;px++){const dx=px-centerX;const distanceSquared=dx*dx+dySquared;if(distanceSquared>radiusSquared)continue;const distance=Math.sqrt(distanceSquared);const lookupIndex=Math.floor(10*distance);const weight=lookupIndex<weightLookup.length?weightLookup[lookupIndex]:0;const matrixIndex=rowIndex+px;const newIntensity=intensityMatrix[matrixIndex]+intensity*weight;intensityMatrix[matrixIndex]=newIntensity;if(newIntensity>maxIntensity)maxIntensity=newIntensity}}}}const intensityThreshold=.001;const invMaxIntensity=maxIntensity>0?1/maxIntensity:0;const colorSteps=256;if(needRecalcColorLookup||!this.colorLookupCache||this.colorLookupCache.length!==colorSteps){this.colorLookupCache=new Array(colorSteps);for(let i=0;i<colorSteps;i++){const ratio=i/(colorSteps-1);this.colorLookupCache[i]=this.interpolateColor(colors,ratio)}}const colorLookup=this.colorLookupCache;for(let i=0;i<intensityMatrix.length;i++){const rawIntensity=intensityMatrix[i];if(rawIntensity<=intensityThreshold)continue;const intensity=rawIntensity*invMaxIntensity;const colorIndex=Math.floor(intensity*(colorSteps-1));const color=colorLookup[colorIndex];const pixelIndex=4*i;pixelData[pixelIndex]=color.r;pixelData[pixelIndex+1]=color.g;pixelData[pixelIndex+2]=color.b;pixelData[pixelIndex+3]=Math.round(255*intensity)}ctx.putImageData(imageData,0,0)}}function fillImageData(canvasWidth,canvasHeight,data,imageData,getColor){if(!data)return;const numRows=data.length;const cellHeight=canvasHeight/numRows;let cellWidth=0;for(let r=0;r<numRows;r++){const rowData=data[r];const numCols=rowData.length;if(0===numCols)continue;if(0===cellWidth)cellWidth=canvasWidth/numCols;const startRow=Math.floor(cellHeight*r);const endRow=Math.ceil(cellHeight*(r+1));for(let c=0;c<numCols;c++){const value=rowData[c];const startCol=Math.floor(cellWidth*c);const endCol=Math.ceil(cellWidth*(c+1));const color=getColor(value);for(let y=startRow;y<endRow;y++){const rowIndex=y*canvasWidth;for(let x=startCol;x<endCol;x++){const index=(rowIndex+x)*4;imageData[index]=color.r;imageData[index+1]=color.g;imageData[index+2]=color.b;imageData[index+3]=color.a}}}}}function getMinMax(numbers){if(!Array.isArray(numbers)||0===numbers.length)throw new Error("Input must be a non-empty array.");let min=numbers[0];let max=numbers[0];for(let i=1;i<numbers.length;i++)if(numbers[i]<min)min=numbers[i];else if(numbers[i]>max)max=numbers[i];return[min,max]}function isNumberAlias(n){return"number"==typeof n&&Number.isFinite(n)}function convertToF64(odata){const flattened=odata.flatMap(row=>{if(0===row.length)return Array(odata[0].length).fill(Number.NaN);return row});return new Float64Array(flattened)}let webgl2Supported=null;function isWebGL2Supported(){if(null!==webgl2Supported)return webgl2Supported;try{const canvas=document.createElement("canvas");const gl=canvas.getContext("webgl2");webgl2Supported=!!gl;if(gl){const ext=gl.getExtension("WEBGL_lose_context");ext?.loseContext()}}catch{webgl2Supported=false}return webgl2Supported}class Gauge extends Engine{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 baseWidth=6;this.updateProps({fillStyle,fillStylePrimary,fillStyleTransparentBase,baseWidth,padding:props.padding??0,step:props.ticksStep??10,lineWidth:1,data:{value:0,limit:0}})}clear(){this.clearRect();const{ctx,BGCanvas}=this.state;if(BGCanvas)ctx.drawImage(BGCanvas,0,0)}resize(){super.resize();if(this.state.lineWidth)this.drawBackground()}render(data){this.state.data={...this.state.data,...data};this.draw()}draw(){const{data:{value},range:[min,max],canvas,ctx,baseWidth,padding,BGCanvas,fillStylePrimary}=this.state;this.clearRect();if(BGCanvas)ctx.drawImage(BGCanvas,0,0);const width=3*baseWidth;const height=canvas.height-2*padding;const x=(canvas.width-width)/2;const renderHeight=(value-min)/(max-min)*height;const y=height-renderHeight+padding;ctx.fillStyle=fillStylePrimary;ctx.fillRect(x,y,width,renderHeight);this.drawLimit()}drawLimit(){const{data:{limit},range:[min,max],canvas,ctx,baseWidth,padding,lineWidth,fillStylePrimary}=this.state;if(!isNumberAlias(limit))return;const width=3*baseWidth;const height=canvas.height-2*padding;const x=(canvas.width-width)/2;const y=height*(max-limit)/(max-min)+padding;const limitTagHeight=9;const triangleWidth=9;const rectangleWidth=30;ctx.beginPath();ctx.moveTo(x+width,y);ctx.lineTo(x+width+triangleWidth,y-limitTagHeight);ctx.lineTo(x+width+triangleWidth+rectangleWidth,y-limitTagHeight);ctx.lineTo(x+width+triangleWidth+rectangleWidth,y+limitTagHeight);ctx.lineTo(x+width+triangleWidth,y+limitTagHeight);ctx.lineTo(x+width,y);ctx.lineTo(x,y);ctx.lineWidth=lineWidth;ctx.strokeStyle=fillStylePrimary;ctx.stroke();ctx.fillStyle=fillStylePrimary;ctx.font="12px Arial";ctx.textAlign="center";ctx.textBaseline="middle";ctx.fillText(limit.toString(),x+width+triangleWidth+rectangleWidth/2,y+1)}drawBackground(){const{canvas,baseWidth,padding,lineWidth,step,range:[min,max],fillStyle,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 width=3*baseWidth;const height=canvas.height-2*padding;const x=(canvas.width-width)/2;const y=padding;const tagNun=11;const markedAngles=Array.from({length:tagNun},(_,i)=>min+Math.round(i*(max-min)/(tagNun-1)/step)*step);BGCtx.fillStyle=fillStyleTransparentBase;BGCtx.fillRect(x,y,width,height);for(let i=min;i<=max;i+=step){const isMarked=markedAngles.includes(i);const tagY=height*(max-i)/(max-min)+padding;BGCtx.beginPath();BGCtx.moveTo(x-(isMarked?baseWidth:baseWidth/2),tagY);BGCtx.lineTo(x,tagY);BGCtx.strokeStyle=fillStyle;BGCtx.lineWidth=isMarked?lineWidth:lineWidth/2;BGCtx.stroke();if(isMarked){BGCtx.fillStyle=fillStyle;BGCtx.font="12px Arial";BGCtx.textAlign="right";BGCtx.textBaseline="middle";BGCtx.fillText(i.toString(),x-1.2*baseWidth,tagY)}}this.state.BGCanvas=BGCanvas}}class WebGLEngine{state;constructor(props){this.state={id:props.id,container:void 0,canvas:null,gl:null,range:props.range??[-20,100]};this.init(props)}updateProps(e){this.state={...this.state,...e}}init(_props){const{id}=this.state;const container=document.getElementById(id);const canvas=document.createElement("canvas");const gl=canvas.getContext("webgl2",{alpha:true,antialias:false,premultipliedAlpha:false,preserveDrawingBuffer:false});if(!gl){console.error("WebGL 2.0 not supported");return}canvas.style.transform="scaleY(-1)";this.updateProps({container:container??void 0,canvas,gl});container?.appendChild(canvas);this.resize(false)}compileShader(type,source){const{gl}=this.state;const shader=gl.createShader(type);if(!shader)return null;gl.shaderSource(shader,source);gl.compileShader(shader);if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){console.error("Shader compile error:",gl.getShaderInfoLog(shader));gl.deleteShader(shader);return null}return shader}createProgram(shaderSource){const{gl}=this.state;const vertexShader=this.compileShader(gl.VERTEX_SHADER,shaderSource.vertex);const fragmentShader=this.compileShader(gl.FRAGMENT_SHADER,shaderSource.fragment);if(!vertexShader||!fragmentShader)return null;const program=gl.createProgram();if(!program)return null;gl.attachShader(program,vertexShader);gl.attachShader(program,fragmentShader);gl.linkProgram(program);if(!gl.getProgramParameter(program,gl.LINK_STATUS)){console.error("Program link error:",gl.getProgramInfoLog(program));gl.deleteProgram(program);return null}gl.deleteShader(vertexShader);gl.deleteShader(fragmentShader);return program}createTexture(){const{gl}=this.state;const texture=gl.createTexture();if(!texture)return null;gl.bindTexture(gl.TEXTURE_2D,texture);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_S,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_WRAP_T,gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.NEAREST);return texture}createQuadBuffer(){const{gl}=this.state;const buffer=gl.createBuffer();if(!buffer)return null;gl.bindBuffer(gl.ARRAY_BUFFER,buffer);const vertices=new Float32Array([-1,-1,1,-1,-1,1,-1,1,1,-1,1,1]);gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);return buffer}clearRect(){const{gl}=this.state;gl.clearColor(0,0,0,0);gl.clear(gl.COLOR_BUFFER_BIT)}resize(draw=true){const{canvas,container,gl}=this.state;if(!container)return;const{clientWidth,clientHeight}=container;if(!clientWidth||!clientHeight)return;canvas.width=clientWidth;canvas.height=clientHeight;gl.viewport(0,0,clientWidth,clientHeight);if(draw)setTimeout(()=>{this.draw()})}draw(){}dispose(){const{gl,canvas}=this.state;if(gl){const loseContext=gl.getExtension("WEBGL_lose_context");if(loseContext)loseContext.loseContext()}canvas?.remove()}}const VERTEX_SHADER=`#version 300 es
|
|
2
2
|
in vec2 a_position;
|
|
3
3
|
out vec2 v_texCoord;
|
|
4
4
|
|
|
@@ -43,78 +43,4 @@ void main() {
|
|
|
43
43
|
// 从颜色查找纹理获取颜色
|
|
44
44
|
fragColor = texture(u_colorTexture, vec2(normalized, 0.5));
|
|
45
45
|
}
|
|
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
|
|
47
|
-
in vec2 a_position;
|
|
48
|
-
uniform vec2 u_resolution;
|
|
49
|
-
uniform float u_rangeMin;
|
|
50
|
-
uniform float u_rangeMax;
|
|
51
|
-
|
|
52
|
-
void main() {
|
|
53
|
-
// x: 归一化到 [-1, 1]
|
|
54
|
-
float x = (a_position.x / u_resolution.x) * 2.0 - 1.0;
|
|
55
|
-
// y: 根据 range 归一化到 [-1, 1]
|
|
56
|
-
float y = ((a_position.y - u_rangeMin) / (u_rangeMax - u_rangeMin)) * 2.0 - 1.0;
|
|
57
|
-
gl_Position = vec4(x, y, 0.0, 1.0);
|
|
58
|
-
}
|
|
59
|
-
`;const SeriesWebGL_FRAGMENT_SHADER=`#version 300 es
|
|
60
|
-
precision highp float;
|
|
61
|
-
uniform vec4 u_color;
|
|
62
|
-
out vec4 fragColor;
|
|
63
|
-
|
|
64
|
-
void main() {
|
|
65
|
-
fragColor = u_color;
|
|
66
|
-
}
|
|
67
|
-
`;const VERTEX_SHADER_WITH_COLOR=`#version 300 es
|
|
68
|
-
in vec2 a_position;
|
|
69
|
-
in vec4 a_color;
|
|
70
|
-
out vec4 v_color;
|
|
71
|
-
uniform vec2 u_resolution;
|
|
72
|
-
uniform float u_rangeMin;
|
|
73
|
-
uniform float u_rangeMax;
|
|
74
|
-
|
|
75
|
-
void main() {
|
|
76
|
-
float x = (a_position.x / u_resolution.x) * 2.0 - 1.0;
|
|
77
|
-
float y = ((a_position.y - u_rangeMin) / (u_rangeMax - u_rangeMin)) * 2.0 - 1.0;
|
|
78
|
-
gl_Position = vec4(x, y, 0.0, 1.0);
|
|
79
|
-
v_color = a_color;
|
|
80
|
-
}
|
|
81
|
-
`;const FRAGMENT_SHADER_WITH_COLOR=`#version 300 es
|
|
82
|
-
precision highp float;
|
|
83
|
-
in vec4 v_color;
|
|
84
|
-
out vec4 fragColor;
|
|
85
|
-
|
|
86
|
-
void main() {
|
|
87
|
-
fragColor = v_color;
|
|
88
|
-
}
|
|
89
|
-
`;const POINT_VERTEX_SHADER=`#version 300 es
|
|
90
|
-
in vec2 a_position;
|
|
91
|
-
uniform vec2 u_resolution;
|
|
92
|
-
uniform float u_rangeMin;
|
|
93
|
-
uniform float u_rangeMax;
|
|
94
|
-
uniform float u_pointSize;
|
|
95
|
-
|
|
96
|
-
void main() {
|
|
97
|
-
float x = (a_position.x / u_resolution.x) * 2.0 - 1.0;
|
|
98
|
-
float y = ((a_position.y - u_rangeMin) / (u_rangeMax - u_rangeMin)) * 2.0 - 1.0;
|
|
99
|
-
gl_Position = vec4(x, y, 0.0, 1.0);
|
|
100
|
-
gl_PointSize = u_pointSize;
|
|
101
|
-
}
|
|
102
|
-
`;const POINT_CIRCLE_FRAGMENT_SHADER=`#version 300 es
|
|
103
|
-
precision highp float;
|
|
104
|
-
uniform vec4 u_color;
|
|
105
|
-
out vec4 fragColor;
|
|
106
|
-
|
|
107
|
-
void main() {
|
|
108
|
-
vec2 coord = gl_PointCoord - vec2(0.5);
|
|
109
|
-
if (length(coord) > 0.5) discard;
|
|
110
|
-
fragColor = u_color;
|
|
111
|
-
}
|
|
112
|
-
`;const POINT_RECT_FRAGMENT_SHADER=`#version 300 es
|
|
113
|
-
precision highp float;
|
|
114
|
-
uniform vec4 u_color;
|
|
115
|
-
out vec4 fragColor;
|
|
116
|
-
|
|
117
|
-
void main() {
|
|
118
|
-
fragColor = u_color;
|
|
119
|
-
}
|
|
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};
|
|
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});gl.enable(gl.BLEND);gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA);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){if(isWebGL2Supported())return new HeatmapWebGL(props);console.warn("[Heatmap] WebGL 2.0 not supported, falling back to Canvas")}return new HeatmapCanvas(props)}const Heatmap_Heatmap=function(props){return createHeatmap(props)};const cartesian_Heatmap=Heatmap_Heatmap;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:DEFAULTS.THICKNESS,display:true,color:DEFAULTS.COLOR,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??DEFAULTS.COLOR);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){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:DEFAULTS.DIAL_NORTH_COLOR,alias:"北"},180:{color:DEFAULTS.DIAL_SOUTH_COLOR,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,color2intensity,createHeatmap,createSeries,hexToRGBA,rgbToHex};
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Fluorescence.d.ts","sourceRoot":"","sources":["../../../src/renderers/cartesian/Fluorescence.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,SAAS,EACT,KAAK,EACN,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"Fluorescence.d.ts","sourceRoot":"","sources":["../../../src/renderers/cartesian/Fluorescence.ts"],"names":[],"mappings":"AACA,OAAO,MAAM,MAAM,mBAAmB,CAAC;AACvC,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,SAAS,EACT,KAAK,EACN,MAAM,aAAa,CAAC;AAMrB,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,MAAM,CAAC,iBAAiB,CAAC;IACjE,IAAI,CAAC,KAAK,EAAE,SAAS;IAYrB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAKzC,cAAc;IAcd,SAAS;IAMT,KAAK;IAQL,OAAO;IAYP,OAAO,CAAC,UAAU;IAmHlB,MAAM;IAKN,QAAQ,CAAC,KAAK,EAAE,KAAK;IAMrB,MAAM,CAAC,IAAI,EAAE,sBAAsB;IASnC,gBAAgB,CACd,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,EAC3D,KAAK,EAAE,MAAM,GACZ;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;IAgDjD,OAAO,CAAC,UAAU,CAA0D;IAG5E,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;IAa1D,OAAO,CAAC,gBAAgB,CAOR;IAGhB,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,gBAAgB,CAA6B;IACrD,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,gBAAgB,CAKP;IAGjB,OAAO,CAAC,mBAAmB,CAIV;IACjB,OAAO,CAAC,qBAAqB,CAMb;IAEhB,IAAI;CAsNL"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Heatmap.d.ts","sourceRoot":"","sources":["../../../src/renderers/cartesian/Heatmap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"Heatmap.d.ts","sourceRoot":"","sources":["../../../src/renderers/cartesian/Heatmap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAIpD,OAAO,aAAa,MAAM,iBAAiB,CAAC;AAE5C,mBAAmB;AACnB,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,KAAK,IAAI,IAAI,CAAC;IACd,MAAM,IAAI,IAAI,CAAC;IACf,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,qBAAqB;AACrB,UAAU,kBAAkB;IAC1B,KAAK,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;IACjC,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAYxD;AAED;;;;;;;;;;GAUG;AACH,QAAA,MAAM,OAAO,EAAE,kBAEQ,CAAC;AAExB,eAAe,OAAO,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -19,19 +19,14 @@ interface SeriesConstructor {
|
|
|
19
19
|
}
|
|
20
20
|
/**
|
|
21
21
|
* 创建 Series 实例
|
|
22
|
-
* 根据 renderer 参数自动选择 Canvas 2D 或 WebGL 实现
|
|
23
22
|
*/
|
|
24
23
|
export declare function createSeries(props: InitProps): ISeries;
|
|
25
24
|
/**
|
|
26
|
-
* Series -
|
|
25
|
+
* Series - Canvas 2D 实现
|
|
27
26
|
* 支持 new Series() 或 Series() 两种调用方式
|
|
28
27
|
*
|
|
29
28
|
* @example
|
|
30
|
-
* // Canvas 2D 版本(默认)
|
|
31
29
|
* const series = new Series({ id: 'canvas', range });
|
|
32
|
-
*
|
|
33
|
-
* // WebGL 版本
|
|
34
|
-
* const series = new Series({ id: 'canvas', range, renderer: RendererType.WebGL });
|
|
35
30
|
*/
|
|
36
31
|
declare const Series: SeriesConstructor;
|
|
37
32
|
export default Series;
|
|
@@ -1 +1 @@
|
|
|
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;
|
|
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;AAClE,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;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAEtD;AAED;;;;;;GAMG;AACH,QAAA,MAAM,MAAM,EAAE,iBAEQ,CAAC;AAEvB,eAAe,MAAM,CAAC;AACtB,OAAO,EAAE,YAAY,EAAE,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Dial.d.ts","sourceRoot":"","sources":["../../../src/renderers/circular/Dial.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Dial.d.ts","sourceRoot":"","sources":["../../../src/renderers/circular/Dial.ts"],"names":[],"mappings":"AACA,OAAO,YAAY,MAAM,gBAAgB,CAAC;AAQ1C;;;GAGG;AACH,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,YAAY;IAC5C,sBAAsB;IACtB,SAAS,CAAC,oBAAoB,CAC5B,KAAK,EAAE,MAAM,GACZ;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS;IAI/C,2BAA2B;IAC3B,SAAS,CAAC,cAAc,IAAI,MAAM;CAGnC"}
|
|
@@ -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;AAwDD,MAAM,CAAC,OAAO,OAAO,YAAa,SAAQ,WAAW,CAAC,iBAAiB,CAAC;IACtE,IAAI,CAAC,KAAK,EAAE,SAAS;
|
|
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;IAoDrB,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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/renderers/webgl/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/renderers/webgl/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAC"}
|
package/types/common.d.ts
CHANGED
|
@@ -25,12 +25,16 @@ export interface Point {
|
|
|
25
25
|
}
|
|
26
26
|
/** 默认值常量 */
|
|
27
27
|
export declare const DEFAULTS: {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
28
|
+
COLOR: string;
|
|
29
|
+
THICKNESS: number;
|
|
30
|
+
FILL_STYLE: string;
|
|
31
|
+
FILL_STYLE_PRIMARY: string;
|
|
32
|
+
FILL_STYLE_TRANSPARENT_BASE: string;
|
|
33
|
+
LINE_COLOR: string;
|
|
34
|
+
POINT_COLOR: string;
|
|
35
|
+
DIAL_NORTH_COLOR: string;
|
|
36
|
+
DIAL_SOUTH_COLOR: string;
|
|
37
|
+
FLUORESCENCE_COLORS: string[];
|
|
38
|
+
RANGE: [number, number];
|
|
35
39
|
};
|
|
36
40
|
//# sourceMappingURL=common.d.ts.map
|
package/types/common.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/types/common.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,gBAAgB;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,8BAA8B;AAC9B,MAAM,MAAM,UAAU,GAClB,MAAM,GACN;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD,sBAAsB;AACtB,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAErC,8BAA8B;AAC9B,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAErD,UAAU;AACV,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,YAAY;AACZ,eAAO,MAAM,QAAQ
|
|
1
|
+
{"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/types/common.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,gBAAgB;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,8BAA8B;AAC9B,MAAM,MAAM,UAAU,GAClB,MAAM,GACN;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEpD,sBAAsB;AACtB,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAErC,8BAA8B;AAC9B,MAAM,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAErD,UAAU;AACV,MAAM,WAAW,KAAK;IACpB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,YAAY;AACZ,eAAO,MAAM,QAAQ;;;;;;;;;;yBA0Bd,MAAM,EAAE;WAGQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACtC,CAAC"}
|
package/utils/index.d.ts
CHANGED
package/utils/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
|
package/utils/webgl.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgl.d.ts","sourceRoot":"","sources":["../../src/utils/webgl.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAoB3C"}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { ColorInterpolator } from '../../color';
|
|
2
|
-
import WebGLEngine, { type WebGLBaseState } from '../../core/WebGLEngine';
|
|
3
|
-
import type { ColorValue, InitProps, Range, SeriesConfig } from '../../types';
|
|
4
|
-
/** SeriesWebGL 状态 */
|
|
5
|
-
export interface SeriesWebGLState extends WebGLBaseState {
|
|
6
|
-
series: Record<string, SeriesConfig>;
|
|
7
|
-
colors: ColorValue[];
|
|
8
|
-
interval: number;
|
|
9
|
-
barValue2Color?: boolean;
|
|
10
|
-
disabledClearRect?: boolean;
|
|
11
|
-
lineProgram: WebGLProgram | null;
|
|
12
|
-
fillProgram: WebGLProgram | null;
|
|
13
|
-
pointProgram: WebGLProgram | null;
|
|
14
|
-
vertexBuffer: WebGLBuffer | null;
|
|
15
|
-
colorTexture: WebGLTexture | null;
|
|
16
|
-
CI: ColorInterpolator | null;
|
|
17
|
-
}
|
|
18
|
-
export default class SeriesWebGL extends WebGLEngine<SeriesWebGLState> {
|
|
19
|
-
private fillProgramWithColor;
|
|
20
|
-
private pointCircleProgram;
|
|
21
|
-
private pointRectProgram;
|
|
22
|
-
private lineUniforms;
|
|
23
|
-
private lineAttribs;
|
|
24
|
-
private fillUniforms;
|
|
25
|
-
private fillAttribs;
|
|
26
|
-
private fillColorUniforms;
|
|
27
|
-
private fillColorAttribs;
|
|
28
|
-
private pointCircleUniforms;
|
|
29
|
-
private pointCircleAttribs;
|
|
30
|
-
private pointRectUniforms;
|
|
31
|
-
private pointRectAttribs;
|
|
32
|
-
private vertexDataBuffer;
|
|
33
|
-
private vertexColorBuffer;
|
|
34
|
-
init(props: InitProps): void;
|
|
35
|
-
/** 缓存所有 shader 的 Uniform/Attribute Locations */
|
|
36
|
-
private cacheLocations;
|
|
37
|
-
updateProps(e: Partial<SeriesWebGLState>): void;
|
|
38
|
-
clear(): void;
|
|
39
|
-
setRange(range: Range): void;
|
|
40
|
-
setIntervel(interval: number): void;
|
|
41
|
-
setSeries(e: SeriesConfig): void;
|
|
42
|
-
render(e: SeriesConfig): void;
|
|
43
|
-
draw(): void;
|
|
44
|
-
private drawLine;
|
|
45
|
-
private uploadAndDrawLineStrip;
|
|
46
|
-
private drawStepline;
|
|
47
|
-
private drawBar;
|
|
48
|
-
private drawBarWithColor;
|
|
49
|
-
private drawArea;
|
|
50
|
-
private drawPoints;
|
|
51
|
-
private drawFilledTrianglesCached;
|
|
52
|
-
private setUniformsCached;
|
|
53
|
-
resize(): void;
|
|
54
|
-
dispose(): void;
|
|
55
|
-
}
|
|
56
|
-
//# sourceMappingURL=SeriesWebGL.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SeriesWebGL.d.ts","sourceRoot":"","sources":["../../../src/renderers/webgl/SeriesWebGL.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAa,MAAM,aAAa,CAAC;AAC3D,OAAO,WAAW,EAAE,EAAE,KAAK,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAkB9E,qBAAqB;AACrB,MAAM,WAAW,gBAAiB,SAAQ,cAAc;IACtD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACrC,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAE5B,WAAW,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,WAAW,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,EAAE,EAAE,iBAAiB,GAAG,IAAI,CAAC;CAC9B;AAoGD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,WAAW,CAAC,gBAAgB,CAAC;IAEpE,OAAO,CAAC,oBAAoB,CAA6B;IACzD,OAAO,CAAC,kBAAkB,CAA6B;IACvD,OAAO,CAAC,gBAAgB,CAA6B;IAGrD,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,YAAY,CAAiC;IACrD,OAAO,CAAC,WAAW,CAAmC;IACtD,OAAO,CAAC,iBAAiB,CAAiC;IAC1D,OAAO,CAAC,gBAAgB,CAAmC;IAC3D,OAAO,CAAC,mBAAmB,CAAiC;IAC5D,OAAO,CAAC,kBAAkB,CAAmC;IAC7D,OAAO,CAAC,iBAAiB,CAAiC;IAC1D,OAAO,CAAC,gBAAgB,CAAmC;IAG3D,OAAO,CAAC,gBAAgB,CAAgD;IACxE,OAAO,CAAC,iBAAiB,CAAgD;IAEzE,IAAI,CAAC,KAAK,EAAE,SAAS;IA8ErB,gDAAgD;IAChD,OAAO,CAAC,cAAc;IAyFtB,WAAW,CAAC,CAAC,EAAE,OAAO,CAAC,gBAAgB,CAAC;IAUxC,KAAK;IAaL,QAAQ,CAAC,KAAK,EAAE,KAAK;IAWrB,WAAW,CAAC,QAAQ,EAAE,MAAM;IAK5B,SAAS,CAAC,CAAC,EAAE,YAAY;IAkBzB,MAAM,CAAC,CAAC,EAAE,YAAY;IAKtB,IAAI;IAmEJ,OAAO,CAAC,QAAQ;IA0EhB,OAAO,CAAC,sBAAsB;IAsB9B,OAAO,CAAC,YAAY;IA6FpB,OAAO,CAAC,OAAO;IAqGf,OAAO,CAAC,gBAAgB;IAuHxB,OAAO,CAAC,QAAQ;IA4FhB,OAAO,CAAC,UAAU;IA4DlB,OAAO,CAAC,yBAAyB;IA2CjC,OAAO,CAAC,iBAAiB;IAgBzB,MAAM;IAIN,OAAO;CAsBR"}
|