您可以通过多种方式自定义连接显示方式,每种方式的难度各不相同。所有这些都需要创建自定义渲染程序。
基本维度
您可以通过更改连接的宽度或高度来自定义连接,同时保持相同的基本形状。为此,您需要创建自定义常量提供程序组件,并替换某些常量。
不同的渲染程序定义和使用不同的常量,因此请查看超类的参考文档:
对于基本渲染程序,您可以替换 NOTCH_WIDTH
和 NOTCH_HEIGHT
(对于下一个和上一个连接)和 TAB_WIDTH
和 TAB_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);
}
}
}
}
}