public getGraphics()

in src/core/prototypes/marks/textbox.ts [334:564]


  public getGraphics(
    cs: Graphics.CoordinateSystem,
    offset: Point,
    // eslint-disable-next-line
    glyphIndex: number,
    // eslint-disable-next-line
    manager: ChartStateManager
  ): Graphics.Element {
    const attrs = this.state.attributes;
    const props = this.object.properties;
    if (
      !attrs.text ||
      (!attrs.color && !attrs.outline) ||
      !attrs.visible ||
      attrs.opacity == 0
    ) {
      return Graphics.makeGroup([]);
    }
    if (!attrs.backgroundColorFilterId) {
      attrs.backgroundColorFilterId = `text-color-filter-${getRandomNumber()}`;
    }
    const metrics = Graphics.TextMeasurer.Measure(
      attrs.text,
      attrs.fontFamily,
      attrs.fontSize
    );
    const helper = new Graphics.CoordinateSystemHelper(cs);
    const cheight = (metrics.middle - metrics.ideographicBaseline) * 2;
    let y = 0;
    switch (props.alignY) {
      case "start":
        {
          y = attrs.y1 - metrics.ideographicBaseline + props.paddingY;
        }
        break;
      case "middle":
        {
          y = attrs.cy - cheight / 2 - metrics.ideographicBaseline;
        }
        break;
      case "end":
        {
          y = attrs.y2 - cheight - metrics.ideographicBaseline - props.paddingY;
        }
        break;
    }
    let textElement: Graphics.Element;
    const applyStyles = (
      textElement: Graphics.TextOnPath,
      attrs: TextboxElementAttributes
    ) => {
      if (attrs.outline) {
        if (attrs.color) {
          const g = Graphics.makeGroup([
            <Graphics.TextOnPath>{
              ...textElement,
              style: {
                strokeColor: attrs.outline,
              },
            },
            <Graphics.TextOnPath>{
              ...textElement,
              style: {
                fillColor: attrs.color,
              },
            },
          ]);
          g.style = { opacity: attrs.opacity };
          return g;
        } else {
          return <Graphics.TextOnPath>{
            ...textElement,
            style: {
              strokeColor: attrs.outline,
              opacity: attrs.opacity,
            },
          };
        }
      } else {
        return <Graphics.TextOnPath>{
          ...textElement,
          style: {
            fillColor: attrs.color,
            opacity: attrs.opacity,
          },
        };
      }
    };
    const textContent = replaceNewLineBySymbol(attrs.text);
    if (
      (textContent && splitStringByNewLine(textContent).length > 1) ||
      props.wordWrap
    ) {
      const height = attrs.fontSize;
      // set limit of lines depends of height bounding box
      let maxLines = 1000;
      // if option enabled and no space for rest of text, set limit of lines count
      if (!props.overFlow) {
        maxLines = Math.floor(Math.abs(attrs.y2 - attrs.y1) / height);
      }

      let textContentList = [textContent];
      // auto wrap text content
      if (props.wordWrap) {
        textContentList = splitByWidth(
          replaceSymbolByTab(replaceSymbolByNewLine(attrs.text)),
          Math.abs(attrs.x2 - attrs.x1) - 10,
          maxLines,
          attrs.fontFamily,
          attrs.fontSize
        );
      }
      // add user input wrap
      textContentList = textContentList.flatMap((line) =>
        splitStringByNewLine(line)
      );
      const lines: Graphics.Element[] = [];
      let textBoxShift = 0;

      switch (props.alignY) {
        case "start":
          {
            switch (props.alignText) {
              case "start":
                textBoxShift = -height;
                break;
              case "middle":
                textBoxShift = (textContentList.length * height) / 2 - height;
                break;
              case "end":
                textBoxShift = textContentList.length * height - height;
                break;
            }
          }
          break;
        case "middle":
          {
            switch (props.alignText) {
              case "start":
                textBoxShift = -height / 2;
                break;
              case "middle":
                textBoxShift =
                  (textContentList.length * height) / 2 - height / 2;
                break;
              case "end":
                textBoxShift = textContentList.length * height - height / 2;
                break;
            }
          }
          break;
        case "end":
          {
            switch (props.alignText) {
              case "start":
                textBoxShift = 0;
                break;
              case "middle":
                textBoxShift = (textContentList.length * height) / 2;
                break;
              case "end":
                textBoxShift = textContentList.length * height;
                break;
            }
          }
          break;
      }

      for (let index = 0; index < textContentList.length; index++) {
        const pathMaker = new Graphics.PathMaker();
        helper.lineTo(
          pathMaker,
          attrs.x1 + offset.x + props.paddingX,
          y + offset.y + textBoxShift - height * index,
          attrs.x2 + offset.x - props.paddingX,
          y + offset.y + textBoxShift - height * index,
          true
        );
        const cmds = pathMaker.path.cmds;

        const textElement = applyStyles(
          <Graphics.TextOnPath>{
            key: index,
            type: "text-on-path",
            pathCmds: cmds,
            text: textContentList[index],
            fontFamily: attrs.fontFamily,
            fontSize: attrs.fontSize,
            align: props.alignX,
          },
          attrs
        );
        lines.push(textElement);
      }

      return Graphics.makeGroup(lines);
    } else {
      const pathMaker = new Graphics.PathMaker();
      helper.lineTo(
        pathMaker,
        attrs.x1 + offset.x + props.paddingX,
        y + offset.y,
        attrs.x2 + offset.x - props.paddingX,
        y + offset.y,
        true
      );
      const cmds = pathMaker.path.cmds;
      textElement = <Graphics.TextOnPath>{
        type: "text-on-path",
        pathCmds: cmds,
        text: attrs.text,
        fontFamily: attrs.fontFamily,
        fontSize: attrs.fontSize,
        align: props.alignX,
      };
      const background = <Graphics.Rect>{
        type: "rect",
        x1: attrs.x1 + offset.x,
        y1: attrs.y1 + offset.y,
        x2: attrs.x2 + offset.x,
        y2: attrs.y2 + offset.y,
        style: {
          fillColor: attrs.backgroundColor,
        },
      };
      return Graphics.makeGroup([
        background,
        applyStyles(<Graphics.TextOnPath>textElement, attrs),
      ]);
    }
  }