連接形狀

您有多種方式可以自訂連線的外觀,而且每種方法的難度都會提高。這些服務都需要建立自訂轉譯器

基本維度

不同維度的連線

您可以調整連線的寬度或高度來自訂連線,同時保持相同的基本形狀。如要這麼做,您必須建立自訂的常數提供者元件,並覆寫某些常數。

不同的轉譯器會定義並使用不同常數,因此請參閱父類別的參考說明文件:

對於基本轉譯器,您可以覆寫下一個和上一個連線的 NOTCH_WIDTHNOTCH_HEIGHT,以及覆寫輸入和輸出連線的 TAB_WIDTHTAB_HEIGHT

class CustomConstantProvider extends Blockly.blockRendering.ConstantProvider {
  constructor() {
    super();
    this.NOTCH_WIDTH = 20;
    this.NOTCH_HEIGHT = 10;
    this.TAB_HEIGHT = 8;
  }
}

基本形狀

不同形狀的連線

您可以覆寫連結的基本形狀來自訂連線。基本形狀包含高度、寬度和路徑。

每個路徑繪製的形狀都相同,但從相反方向繪製!

從兩個方向繪製的凹槽

這是必要的,因為導覽匣會繪製區塊的外框,因此會雙向繪製每種連線類型。例如,先前的連線是從左到右繪製,但下一個連線會從右至左繪製。因此,您需要提供這兩種情況的路徑。

方塊繪製方向

您可以覆寫下一個和上一個連線的 makeNotch 方法,以及輸入和輸出連線的 makePuzzleTab 方法。

class CustomConstantProvider extends Blockly.blockRendering.ConstantProvider {
  makePuzzleTab() {
    const width = this.TAB_WIDTH;
    const height = this.TAB_HEIGHT;
    return {
      type: this.SHAPES.PUZZLE,
      width,
      height,
      pathUp: Blockly.utils.svgPaths.line([
          Blockly.utils.svgPaths.point(-width, -height / 2),
          Blockly.utils.svgPaths.point(width, -height / 2)]),
      pathDown: Blockly.utils.svgPaths.line([
          Blockly.utils.svgPaths.point(-width, height / 2),
          Blockly.utils.svgPaths.point(width, height / 2)]),
    };
  }
}

如要瞭解如何定義路徑字串,請參閱 MDN SVG 路徑說明文件。提供 Blockly.utils.svgPaths 命名空間做為這些字串的細包裝函式,使名稱更容易閱讀。

連線檢查的形狀

不同形狀之間的關聯

您可以根據連線的連線檢查變更形狀來自訂連線。

這可讓您建立不同的形狀來代表不同的資料類型。例如,字串可能以三角形連線表示,而布林值則以圓形連線表示。

如要為不同的連線檢查提供不同的形狀,您必須覆寫 shapeFor 方法。傳回的形狀應在 init 中初始化。

如要瞭解支援的形狀類型,請參閱「基本形狀」。

export class ConstantProvider extends Blockly.blockRendering.BaseConstantProvider {
  shapeFor(connection) {
    let check = connection.getCheck();
    // For connections with no check, match any child block.
    if (!check && connection.targetConnection) {
      check = connection.targetConnection.getCheck();
    }

    if (check && check.includes('String')) return this.TRIANGULAR_TAB;
    if (check && check.includes('Boolean')) return this.ROUND_TAB;

    return super.shapeFor(connection);
  }
}

自訂輸入內容

您可以建立自訂輸入來源來自訂連線形狀。只有當您希望某些連線與其他連線不同時,您才會這麼做,但不希望其根據連線檢查加以根據。

舉例來說,如果您希望某些值輸入能以類似陳述式輸入縮排,您可以建立自訂輸入來支援此功能。

建立自訂輸入類別

按照建立自訂輸入的步驟操作。

建立可評估的指標

您必須建立可評估來代表自訂輸入內容。

可測量的自訂輸入內容應繼承自 Blockly.blockRendering.InputConnection。也可包含繪製輸入內容形狀所需的任何額外測量資料。

export class CustomInputMeasurable extends Blockly.blockRendering.InputConnection {
  constructor(constants, input) {
    super(constants, input);

    // Any extra measurement data...
  }
}

將可評估的成效指標例項化

您的轉譯資訊需要對自訂的測量結果執行個體化。如要這麼做,您必須覆寫 addInput_ 方法。

export class RenderInfo extends Blockly.blockRendering.RenderInfo {
  addInput_(input, activeRow) {
    if (input instanceof CustomInput) {
      activeRow.elements.push(new CustomInputMeasurable(this.constants_, input));
    }
    super.addInput_(input, activeRow);
  }
}

視需要建立資料列

根據預設,輸入內容不會建立新的資料列。如果您希望輸入內容觸發資料列結尾,就必須覆寫轉譯資訊shouldStartNewRow_ 方法。

export class RenderInfo extends Blockly.blockRendering.RenderInfo {
  shouldStartNewRow_(currInput, prevInput) {
    if (prevInput instanceof CustomInput) return true;
    return super.shouldStartNewRow_(currInput, prevInput);
  }
}

視需要為輸入內容建立形狀

建議您以常數方式儲存輸入內容的形狀,就像儲存凹槽和益智分頁一樣。這樣做可讓程式碼保持井然有序,也可以方便日後修改。

繪製輸入

最後,您必須修改導覽匣才能繪製形狀。

自訂輸入內容可採用下列其中一種做法:

  • 影響區塊的輪廓,例如陳述輸入內容

    外框輸入圖片

  • 或是影響區塊的內部,例如內嵌值輸入內容

    內部輸入來源圖片

如果輸入內容會影響區塊的外框,請覆寫 drawOutline_,否則覆寫 drawInternals_

export class Drawer extends Blockly.blockRendering.Drawer {
  drawOutline_() {
    this.drawTop_();
    for (let r = 1; r < this.info_.rows.length - 1; r++) {
      const row = this.info_.rows[r];

      // Insert checks for your input here!
      if (row.getLastInput() instanceof CustomInputMeasurable) {
        this.drawCustomInput(row);
      } else if (row.hasJaggedEdge) {
        this.drawJaggedEdge_(row);
      } else if (row.hasStatement) {
        this.drawStatementInput_(row);
      } else if (row.hasExternalInput) {
        this.drawValueInput_(row);
      } else {
        this.drawRightSideRow_(row);
      }
    }
    this.drawBottom_();
    this.drawLeft_();
  }

  protected drawInternals_() {
    for (const row of rows) {
      for (const elem of row) {

        // Insert checks for your input here!
        if (elem instanceof CustomInputMeasurable) {
          this.drawCustomInput(elem);
        }

        if (Types.isInlineInput(elem)) {
          this.drawInlineInput_(elem as InlineInput);
        } else if (Types.isIcon(elem) || Types.isField(elem)) {
          this.layoutField_(elem as Field | Icon);
        }
      }
    }
  }
}