راههای مختلفی وجود دارد که میتوانید ظاهر اتصالات را سفارشی کنید، که هر کدام با دشواریهای فزایندهای همراه هستند. همه آنها نیاز به ایجاد یک رندر سفارشی دارند.
ابعاد پایه
می توانید اتصالات را با تغییر عرض یا ارتفاع آنها سفارشی کنید، در حالی که همان شکل اولیه را حفظ کنید. برای انجام این کار، باید یک مؤلفه ارائه دهنده ثابت سفارشی ایجاد کنید و برخی از ثابت ها را لغو کنید.
رندرهای مختلف ثابت های مختلفی را تعریف و استفاده می کنند، بنابراین مستندات مرجع برای کلاس فوق العاده خود را بررسی کنید:
برای رندر پایه، می توانید 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);
}
}
}
}
}