Há várias maneiras de personalizar a aparência das conexões, cada uma com cada vez mais dificuldade. Todos eles exigem a criação de um renderizador personalizado.
Dimensões básicas
Você pode personalizar as conexões mudando a largura ou altura delas, mantendo a mesma forma básica. Para isso, você precisa criar um componente personalizado de provedor de constante e substituir algumas constantes.
Diferentes renderizadores definem e usam constantes diferentes. Portanto, confira a documentação de referência da sua superclasse:
- constantes de base
- Constantes de gerações (link em inglês)
- Constantes Zelos (link em inglês)
Para o renderizador base, você pode substituir NOTCH_WIDTH
e
NOTCH_HEIGHT
para conexões seguintes e anteriores, e
TAB_WIDTH
e TAB_HEIGHT
para conexões de entrada
e saída.
class CustomConstantProvider extends Blockly.blockRendering.ConstantProvider {
constructor() {
super();
this.NOTCH_WIDTH = 20;
this.NOTCH_HEIGHT = 10;
this.TAB_HEIGHT = 8;
}
}
Formas básicas
Você pode personalizar as conexões substituindo o formato básico delas. As formas básicas têm altura, largura e dois caminhos.
Cada caminho desenha a mesma forma, mas de extremidades opostas!
Isso é necessário porque, como a gaveta desenha o contorno do bloco, ela desenha cada tipo de conexão nas duas direções. Por exemplo, as conexões anteriores são desenhadas da esquerda para a direita, enquanto as próximas são desenhadas da direita para a esquerda. Portanto, é preciso fornecer caminhos para esses dois casos.
Você pode substituir o método makeNotch
para as conexões seguintes e anteriores, e o método makePuzzleTab
para conexões de entrada e saída.
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)]),
};
}
}
Confira a documentação de caminho do MDN SVG para informações sobre como
definir strings de caminho. O namespace Blockly.utils.svgPaths
é fornecido
como um wrapper fino em torno dessas strings para torná-las mais legíveis.
Formas para verificações de conexão
Você pode personalizar as conexões alterando a forma com base na verificação de conexão da conexão.
Isso permite criar formas diferentes para representar tipos de dados distintos. Por exemplo, strings podem ser representadas por conexões triangulares, enquanto booleanos são representados por conexões redondas.
Para fornecer formas diferentes em diversas verificações de conexão, é necessário modificar o método shapeFor
. As formas retornadas precisam ser inicializadas em init
.
Consulte formas básicas para ver informações sobre os tipos compatíveis.
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);
}
}
Entradas personalizadas
Você pode criar uma entrada totalmente personalizada para personalizar os formatos de conexão. Isso só será feito se você quiser que algumas conexões pareçam diferentes de outras, mas não quiser que isso seja baseado na verificação de conexão.
Por exemplo, se você quiser que algumas entradas de valor sejam recuadas como entradas de instrução, crie uma entrada personalizada para ser compatível com isso.
Criar uma classe de entrada personalizada
Siga as etapas para criar uma entrada personalizada.
Crie um design
Você precisa criar uma entrada mensurável para representar sua entrada personalizada.
A entrada mensurável personalizada precisa herdar de
Blockly.blockRendering.InputConnection
. Ela também pode incluir
quaisquer dados de medição extras necessários para desenhar a forma da entrada.
export class CustomInputMeasurable extends Blockly.blockRendering.InputConnection {
constructor(constants, input) {
super(constants, input);
// Any extra measurement data...
}
}
Instancie suas campanhas mensuráveis
As informações de renderização precisam instanciar a medição personalizada. Para fazer isso, substitua o método 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);
}
}
Como opção, crie uma linha
Por padrão, as entradas não criam novas linhas. Se você quiser que a entrada
acione o fim de uma linha, modifique o método
shouldStartNewRow_
das
informações de renderização.
export class RenderInfo extends Blockly.blockRendering.RenderInfo {
shouldStartNewRow_(currInput, prevInput) {
if (prevInput instanceof CustomInput) return true;
return super.shouldStartNewRow_(currInput, prevInput);
}
}
Como opção, crie uma forma para a entrada
É uma boa ideia armazenar a forma da entrada de forma constante, como fazemos para entalhes e guias de quebra-cabeças. Isso mantém seu código organizado e facilita modificações posteriores.
Desenhar a entrada
Por fim, é necessário modificar sua gaveta para desenhar a forma.
As entradas personalizadas podem:
afetar o contorno do seu bloco, como entradas de instrução
Ou afetar os componentes internos do bloco, como entradas de valores inline
Se a entrada afetar o contorno do bloco, substitua
drawOutline_
. Caso contrário, substitua
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);
}
}
}
}
}