inlann commented on issue #13664:
URL: https://github.com/apache/echarts/issues/13664#issuecomment-1491214480

   @FreidoGit Hi.
   
   > I implemented a smith chart using Echarts:
   
   The following code is the initial version:
   
   ```typescript
   /**
    * Smith Chart calculation:
    * known:
    * real, imag, PI, W(diameter of max circle, equals to Math.atan(Infinity)),
    *
    * unknown:
    * alfa(the angle alfa between the imag circle and the outermost real 
circle(max circle)),
    * beta(the angle alfa between the imag circle and the needed real circle),
    * rImag(radius of the imag circle),
    * rReal(radius of the real circle)
    * x, y,
    *
    * steps:
    * alfa = atan(imag) / atan(Infinity) * PI,
    * rImag = atan(Infinity) / 2 / atan(alfa / 2),
    * rReal = (atan(Infinity) - atan(real)) / 2,
    * beta = 2 * atan(rReal / rImag),
    * x = atan(Infinity) - rReal - rReal * cos(beta),
    * y = rReal * sin(beta),
    */
   
   import * as React from 'react';
   import ReactECharts from 'echarts-for-react';
   
   export interface ComplexNumber {
       real: number,
       imag: number,
   }
   
   export interface SmithChartProps {
       r: number,
       smithChartData: ComplexNumber[],
   }
   
   /** this interface maybe need to add some properties */
   export interface SimthChartStates {
       r: number,
       smithChartdata: ComplexNumber[],
   }
   
   const tan = Math.tan;
   const atan = Math.atan;
   const sin = Math.sin;
   const cos = Math.cos;
   const PI = Math.PI;
   
   export class SmithChartComponent extends React.Component<SmithChartProps, 
SimthChartStates>{
       private readonly COMPONENT_CLASS: string = 'smith-chart';
   
       constructor(props: SmithChartProps) {
           super(props);
           this.state = {
               r: 0,
               smithChartdata: [],
           };
       }
   
       componentDidMount() {
           this.setState({
               r: this.props.r,
               smithChartdata: this.props.smithChartData
           });
       }
   
       protected drawTheGraphicsWithNumber(aAixsLabels: string[]) {
           const children = [];
   
           const splitNumber = aAixsLabels.length;
   
           /** draw */
           children.push({
               type: 'circle',
               id: 'bg_circle',
               silent: false,
               style: {
                   fill: undefined,
                   stroke: 'gray',
               },
               shape: {
                   r: this.state.r,
               }
           });
   
           for (let i = 1; i <= splitNumber; i++) {
               /** draw the circles */
               children.push({
                   type: 'circle',
                   id: 'real_cir_' + String(i),
                   silent: true,
                   style: {
                       fill: undefined,
                       stroke: 'gray',
                       lineStyle: {
                           type: 'dotted',
                       }
                   },
                   shape: {
                       cx: (this.state.r / (splitNumber + 1)) * i,
                       r: this.state.r - (this.state.r / (splitNumber + 1) ) * 
i,
                       clockwise: true,
                   }
               });
   
               /** draw the top arcs */
               children.push({
                   type: 'arc',
                   id: 'imag_arc_top_' + String(i),
                   silent: true,
                   style: {
                       fill: undefined,
                       stroke: 'gray',
                   },
                   shape: {
                       cx: this.state.r,
                       cy: - this.state.r * tan(PI * i / (splitNumber + 1) / 2),
                       r: this.state.r * tan(PI * i / (splitNumber + 1) / 2),
                       startAngle: PI / 2,
                       endAngle: (3 / 2 - i / (splitNumber + 1)) * PI,
                       clockwise: true,
                   }
               });
   
               /** draw the bottom arcs */
               children.push({
                   type: 'arc',
                   id: 'imag_arc_bot_' + String(i),
                   silent: true,
                   style: {
                       fill: undefined,
                       stroke: 'gray',
                   },
                   shape: {
                       cy: this.state.r * tan(PI * i / (splitNumber + 1) / 2),
                       cx: this.state.r,
                       r: this.state.r * tan(PI * i / (splitNumber + 1) / 2),
                       startAngle:  (1 / 2 + i / (splitNumber + 1)) * PI,
                       endAngle: PI * 3 / 2,
                       clockwise: true,
                   }
               });
   
               /**
                * draw the top text
                * FIXME: fix the style of the imag text.
                */
               children.push({
                   type: 'text',
                   id: 'imag_text_top_' + String(i),
                   silent: true,
                   style: {
                       text: aAixsLabels[splitNumber - i] + 'i',
                       x: this.state.r * cos(PI * i / (splitNumber + 1)),
                       y: -this.state.r * sin(PI * i / (splitNumber + 1)),
                       fill: undefined,
                       stroke: 'gray'
                   }
               });
   
               /** draw the bottom text */
               children.push({
                   type: 'text',
                   id: 'imag_text_bot_' + String(i),
                   silent: true,
                   style: {
                       text: '-' + aAixsLabels[splitNumber - i] + 'i',
                       x: this.state.r * cos(PI * i / (splitNumber + 1)),
                       y: this.state.r * sin(PI * i / (splitNumber + 1)),
                       fill: undefined,
                       stroke: 'gray'
                   }
               });
           }
   
           return children;
       }
   
       protected generateSmithChartGraphic(aAixsLabels: string[]) {
           const children = this.drawTheGraphicsWithNumber(aAixsLabels);
   
           return {
               type: 'group',
               id: 'smith_group',
               /** FIXME: fix the hard code right and top */
               right: 87,
               top: 57,
               draggable: true,
               children: children,
           };
       }
   
       protected convertPosition(complexNumber: ComplexNumber) {
           const real = complexNumber.real;
           const imag = complexNumber.imag;
   
           if (imag === 0) {
               return [atan(real), 0];
           }
   
           /**
            * Calculate the angle alfa between the imag circle and the 
outermost real circle
            * by calculating the proportion of the imag number on the outermost 
circle, and
            * then calculate the radius of the imag circle (to determine the 
center of the
            * imaginary circle).
            */
           const alfa = atan(imag) / atan(Infinity) * PI;
           const rImag = atan(Infinity) / 2 / tan(alfa / 2);
   
           /**
            * By calculating the angle beta between the imaginary circle and 
the real circle,
            * we can finally calculate the values of x and y
            */
           const rReal = (atan(Infinity) - atan(real)) / 2;
           const beta = 2 * atan(rReal / rImag);
           const x = atan(Infinity) - rReal - rReal * cos(beta);
           const y = rReal * sin(beta);
   
           return [x, y];
       }
   
       protected calculateComplexNumber(x: number, y: number): [string, string] 
{
           if (y === 0) {
               return [tan(x).toFixed(2), '0'];
           }
   
           /** Reverse the calculation of x and y to restore the complex number 
*/
           const beta =  2 * atan(y / (atan(Infinity) - x));
           const rReal = y / sin(beta);
           const real = tan(atan(Infinity) - 2 * rReal).toFixed(2);
   
           const rImag = rReal / tan(beta / 2);
           const alfa = 2 * atan(atan(Infinity) / 2 / rImag);
           const imag = tan(alfa / PI * atan(Infinity)).toFixed(2);
   
           return [real, imag];
       }
   
       protected generateLabelArray(length: number): string[] {
           const resultArray: string[] = [];
           for (let i = 1; i <= length ; i++) {
               resultArray.push(tan(PI * i / 2 / (length + 1)).toFixed(2));
           }
           return resultArray;
       }
   
       protected generateSimthChartOptions() {
           /** the `splitNumber` is related to datazoom */
           const splitNumber = 7;
   
           const aAixsLabels = this.generateLabelArray(splitNumber);
           const xAxisLabels = [0, ...aAixsLabels];
   
           return {
               title: {
                   text: 'Smith Chart',
                   left: 'center',
               },
               legend: [{
                   // eslint-disable-next-line id-blacklist
                   data: ['simth']
               }],
               tooltip: {
                   /** FIXME: fix the type of value */
                   formatter: (value: { value: number[]; }) => {
                       const complexNumber = 
this.calculateComplexNumber(value.value[0], value.value[1]);
                       return complexNumber[0] + ', ' + complexNumber[1] + 'i';
                   }
               },
               grid: {
                   width: 2 * this.state.r,
                   height: 2 * this.state.r
               },
               xAxis: {
                   type: 'value',
                   position: 'bottom',
                   splitNumber: 5,
                   max: atan(Infinity),
                   min: 0,
                   interval: atan(Infinity) / xAxisLabels.length,
                   offset: - this.state.r,
                   axisLabel: {
                       formatter: (_: number, index: number) => 
xAxisLabels[index]
                   }
               },
               yAxis: {
                   type: 'value',
                   show: true,
                   max: atan(Infinity) / 2,
                   min: - atan(Infinity) / 2,
               },
               graphic: this.generateSmithChartGraphic(aAixsLabels),
               series: [
                   {
                       type: 'line',
                       smooth: true,
                       // eslint-disable-next-line id-blacklist
                       data: this.state.smithChartdata.map((complexNumber: 
ComplexNumber) => this.convertPosition(complexNumber))
                   }
               ]
           };
       }
   
       public render(): JSX.Element{
           return(
               /**
                * FIXME: fix the size of chart to be flexible.
                */
               <div className={this.COMPONENT_CLASS} style={{ width: 1100, 
height: 1100 }}>
                   <ReactECharts option={this.generateSimthChartOptions()} 
style={{ height: '100%' }} />
               </div>
           );
       }
   }
   ```
   
   Sorry, I didn't have enough time to support chart features like datazoom so 
that I didn't use it in our project 😢 
   
   We change to use Geo chart and draw some svg lines to implement the smith 
chart:


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org
For additional commands, e-mail: commits-h...@echarts.apache.org

Reply via email to