Build custom renderers
7. Change connection shapes
This step will define and use new shapes for previous/next connections and input/output connections. This takes three steps:
- Define new shape objects.
- Override
init()to store the new shape objects. - Override
shapeFor(connection)to return the new objects.
Define a previous/next connection shape
An outline path is drawn clockwise around the block, starting at the top left. As a result the previous connection is drawn from left-to-right, while the next connection is drawn from right-to-left.
Previous and next connections are defined by the same object. The object has four properties:
width: The width of the connection.height: The height of the connection.pathLeft: The sub-path that describes the connection when drawn from left-to-right.pathRight: The sub-path that describes the connection when drawn from right-to-left.
Define a new function called makeRectangularPreviousConn() and put it inside the CustomConstantProvider class definition. Note that NOTCH_WIDTH and NOTCH_HEIGHT have already been overridden in the constructor(), so they'll be reused:
/**
* @returns Rectangular notch for use with previous and next connections.
*/
makeRectangularPreviousConn() {
const width = this.NOTCH_WIDTH;
const height = this.NOTCH_HEIGHT;
/**
* Since previous and next connections share the same shape you can define
* a function to generate the path for both.
*
* @param dir Multiplier for the horizontal direction of the path (-1 or 1)
* @returns SVGPath line for use with previous and next connections.
*/
function makeMainPath(dir) {
return Blockly.utils.svgPaths.line(
[
Blockly.utils.svgPaths.point(0, height),
Blockly.utils.svgPaths.point(dir * width, 0),
Blockly.utils.svgPaths.point(0, -height),
]);
}
const pathLeft = makeMainPath(1);
const pathRight = makeMainPath(-1);
return {
width: width,
height: height,
pathLeft: pathLeft,
pathRight: pathRight,
};
}
Define an input/output connection shape
Just as previous/next connection shapes are drawn from left-to-right and right-to-left, input/output connection shapes are drawn from top-to-bottom and bottom-to-top.
Input and output connections are defined by the same object. The object has four properties:
width: The width of the connection.height: The height of the connection.pathUp: The sub-path that describes the connection when drawn from top-to-bottom.pathDown: The sub-path that describes the connection when drawn from bottom-to-top.
Define a new function called makeRectangularInputConn() and put it inside the CustomConstantProvider class definition. Note that TAB_WIDTH and TAB_HEIGHT have already been overridden in the constructor() so they'll be reused:
/**
* @returns Rectangular puzzle tab for use with input and output connections.
*/
makeRectangularInputConn() {
const width = this.TAB_WIDTH;
const height = this.TAB_HEIGHT;
/**
* Since input and output connections share the same shape you can define
* a function to generate the path for both.
*
* @param dir Multiplier for the vertical direction of the path (-1 or 1)
* @returns SVGPath line for use with input and output connections.
*/
function makeMainPath(dir) {
return Blockly.utils.svgPaths.line(
[
Blockly.utils.svgPaths.point(-width, 0),
Blockly.utils.svgPaths.point(0, dir * height),
Blockly.utils.svgPaths.point(width, 0),
]);
}
const pathUp = makeMainPath(-1);
const pathDown = makeMainPath(1);
return {
width: width,
height: height,
pathUp: pathUp,
pathDown: pathDown,
};
}
Override init()
Override the init() function in the CustomConstantProvider class definition and store the new shape objects as RECT_PREV_NEXT and RECT_INPUT_OUTPUT. Make sure to call the superclass init() function to store other objects that have not been overridden.
/**
* @override
*/
init() {
// First, call init() in the base provider to store the default objects.
super.init();
// Add calls to create shape objects for the new connection shapes.
this.RECT_PREV_NEXT = this.makeRectangularPreviousConn();
this.RECT_INPUT_OUTPUT = this.makeRectangularInputConn();
}
Override shapeFor(connection)
Next, override the shapeFor(connection) function in the CustomConstantProvider class definition and return the new custom objects:
/**
* @override
*/
shapeFor(connection) {
switch (connection.type) {
case Blockly.INPUT_VALUE:
case Blockly.OUTPUT_VALUE:
return this.RECT_INPUT_OUTPUT;
case Blockly.PREVIOUS_STATEMENT:
case Blockly.NEXT_STATEMENT:
return this.RECT_PREV_NEXT;
default:
throw Error('Unknown connection type');
}
}
The result
Return to the browser, click on the Loops entry, and drag out a repeat block. The resulting block should have rectangular connections for all four connection types.
![[Screenshot of a custom renderer with notches, corners, and tabs with fundamentally different shapes than the defaults.]](/blockly/assets/images/custom_notches-748382ef4ccf775077b52652143f70c5.png)