Существует несколько способов настройки внешнего вида соединений, сложность каждого из которых возрастает. Все они требуют создания собственного средства визуализации .
Основные размеры
Вы можете настроить соединения, изменив их ширину или высоту, сохраняя при этом ту же базовую форму. Для этого вам необходимо создать собственный компонент поставщика констант и переопределить некоторые константы.
Разные средства визуализации определяют и используют разные константы, поэтому ознакомьтесь со справочной документацией для вашего суперкласса:
Для базового средства визуализации вы можете переопределить 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);
}
}
}
}
}