一、背景

由于scratch blocks 自带的mictobit点阵只支持5*5,有时候并不满足我们自己的硬件,为此设计了N*M点阵Block,效果如下:

二、功能配置说明

支持N行M列点阵

支持保存历史图案

支持内置图案设置

配置说明:

// 点阵行数
Blockly.FieldMatrixCustom.MATRIX_ROW = 8;
// 点阵列数
Blockly.FieldMatrixCustom.MATRIX_COL = 16;
// 缩略点阵LED的大小(px)
Blockly.FieldMatrixCustom.THUMBNAIL_NODE_SIZE = 2;
// 缩略点阵中每个LED的间距(px)
Blockly.FieldMatrixCustom.THUMBNAIL_NODE_PAD = 1;
// 下拉箭头大小
Blockly.FieldMatrixCustom.ARROW_SIZE = 12;
// 点阵LED的大小(px)
Blockly.FieldMatrixCustom.MATRIX_NODE_SIZE = 18;
// 点阵LED的圆角(px)
Blockly.FieldMatrixCustom.MATRIX_NODE_RADIUS = 4;
// 点阵LED的间距(px)
Blockly.FieldMatrixCustom.MATRIX_NODE_PAD = 5;

内置图案配置,直接在对象中以Key,Value形式添加即可,会自动渲染

Blockly.FieldMatrixCustom.LEDS = {// 全灭ZEROS: "".padEnd(Blockly.FieldMatrixCustom.MATRIX_ROW * Blockly.FieldMatrixCustom.MATRIX_COL, "0"),// 全亮FULLS: "".padEnd(Blockly.FieldMatrixCustom.MATRIX_ROW * Blockly.FieldMatrixCustom.MATRIX_COL, "1"),// HELLO样式HELLO: "10100000101000001010000010100000101000001010000010101110101001101110101010101001101011101010100110101000101010011010111010100110",// 实心HEART: "00001110011100000001111111111000000111111111100000011111111110000000111111110000000001111110000000000011110000000000000110000000",// 空心HEART_OUT_LINE: "00001110011100000001000110001000000100000000100000010000000010000000100000010000000001000010000000000010010000000000000110000000",// 添加其他,会自动渲染// Add Others...
};

三、使用说明

(1)引入field_matrix_custom.js

(2)引入css样式,代码在文章末尾

(3)定义Block,代码如下:

Blockly.Blocks['matrix_custom'] = {init: function() {this.jsonInit({"message0": "%1","args0": [{"type": "field_matrix_custom","name": "MATRIX_CUSTOM"}],"outputShape": Blockly.OUTPUT_SHAPE_ROUND,"output": "Number","extensions": ["colours_pen"]});}
};
Blockly.Blocks['extend_matrix'] = {init: function() {this.jsonInit({"message0": "%1 %2 显示点阵 %3","args0": [{"type": "field_image","src": Blockly.mainWorkspace.options.pathToMedia + "extensions/matrix.svg","width": 32,"height": 32},{"type": "field_vertical_separator"},{"type": "input_value","name": "MATRIX_CUSTOM"},],"category": Blockly.Categories.pen,"extensions": ["colours_pen", "shape_statement", "scratch_extension"]});}
};

(4)添加toolbox配置,代码如下:

<block type="extend_matrix" id="extend_matrix"><value name="MATRIX_CUSTOM"><shadow type="matrix_custom"><field name="MATRIX_CUSTOM">0000000000</field></shadow></value>
</block>

四、效果展示

8*16

8*8

8*32

五、完整代码

完整field_matrix_custom.js代码如下:

'use strict';goog.provide('Blockly.FieldMatrixCustom');
goog.require('Blockly.DropDownDiv');/*** 构造* @param matrix* @constructor*/
Blockly.FieldMatrixCustom = function(matrix) {Blockly.FieldMatrixCustom.superClass_.constructor.call(this, matrix);this.addArgType('matrix');// 块字段上矩阵缩略图数组。this.ledThumbNodes_ = [];// 下拉菜单中矩阵编辑器的数组。this.ledButtons_ = [];// 用于存储当前矩阵值的字符串this.matrix_ = '';// 编辑器中LED矩阵this.matrixStage_ = null;// 下拉箭头this.arrow_ = null;// 指示矩阵绘制样式的字符串this.paintStyle_ = null;// 鼠标按下事件this.mouseDownWrapper_ = null;// 触摸事件(用于设置LED状态)this.matrixTouchWrapper_ = null;// 鼠标移动事件(用于设置LED状态)this.matrixMoveWrapper_ = null;// 鼠标释放事件(用于设置LED状态)this.matrixReleaseWrapper_ = null;
};// 继承 Blockly.Field)
goog.inherits(Blockly.FieldMatrixCustom, Blockly.Field);/*** 通过JSON生成*/
Blockly.FieldMatrixCustom.fromJson = function(options) {return new Blockly.FieldMatrixCustom(options['matrix']);
};/*** 矩阵行数*/
Blockly.FieldMatrixCustom.MATRIX_ROW = 8;/*** 矩阵列数*/
Blockly.FieldMatrixCustom.MATRIX_COL = 16;/*** 缩略点阵LED的大小(px)*/
Blockly.FieldMatrixCustom.THUMBNAIL_NODE_SIZE = 2;/*** 缩略点阵中每个LED的间距(px)*/
Blockly.FieldMatrixCustom.THUMBNAIL_NODE_PAD = 1;/*** 下拉箭头大小*/
Blockly.FieldMatrixCustom.ARROW_SIZE = 12;/*** 点阵LED的大小(px)* @type {number}*/
Blockly.FieldMatrixCustom.MATRIX_NODE_SIZE = 18;/*** 点阵LED的圆角(px)* @type {number}*/
Blockly.FieldMatrixCustom.MATRIX_NODE_RADIUS = 4;/*** 点阵LED的间距(px)* @type {number}*/
Blockly.FieldMatrixCustom.MATRIX_NODE_PAD = 5;/*** 所有内置的,用户无法删除的*/
Blockly.FieldMatrixCustom.LEDS = {// 全灭ZEROS: "".padEnd(Blockly.FieldMatrixCustom.MATRIX_ROW * Blockly.FieldMatrixCustom.MATRIX_COL, "0"),// 全亮FULLS: "".padEnd(Blockly.FieldMatrixCustom.MATRIX_ROW * Blockly.FieldMatrixCustom.MATRIX_COL, "1"),// HELLO样式HELLO: "10100000101000001010000010100000101000001010000010101110101001101110101010101001101011101010100110101000101010011010111010100110",// 实心HEART: "00001110011100000001111111111000000111111111100000011111111110000000111111110000000001111110000000000011110000000000000110000000",// 空心HEART_OUT_LINE: "00001110011100000001000110001000000100000000100000010000000010000000100000010000000001000010000000000010010000000000000110000000",// 添加其他,会自动渲染// Add Others...
};/*** 用户自己保存的,可以由用户随意删除* 每次由本地读取* @type {{}}*/
Blockly.FieldMatrixCustom.USER = JSON.parse(localStorage.getItem("USER_CUSTOM_MATRIX")) || {};/*** 初始化*/
Blockly.FieldMatrixCustom.prototype.init = function() {if (this.fieldGroup_) {return;}// 创建字段this.fieldGroup_ = Blockly.utils.createSvgElement('g', {}, null);this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_);// 计算字段宽度 缩略点阵加下拉箭头所占的区域this.size_.width = (Blockly.FieldMatrixCustom.THUMBNAIL_NODE_SIZE + Blockly.FieldMatrixCustom.THUMBNAIL_NODE_PAD) *Blockly.FieldMatrixCustom.MATRIX_COL +Blockly.FieldMatrixCustom.ARROW_SIZE + Blockly.BlockSvg.DROPDOWN_ARROW_PADDING * 1.5;// 计算字段高度this.size_.height = (Blockly.FieldMatrixCustom.THUMBNAIL_NODE_SIZE + Blockly.FieldMatrixCustom.THUMBNAIL_NODE_PAD) *Blockly.FieldMatrixCustom.MATRIX_ROW + 10;// 创建缩略点阵var thumbnail = Blockly.utils.createSvgElement('g', {'transform': 'translate(5, 5)','pointer-events': 'bounding-box', 'cursor': 'pointer'}, this.fieldGroup_);// 创建缩略点阵LEDthis.ledThumbNodes_ = [];var nodeSize = Blockly.FieldMatrixCustom.THUMBNAIL_NODE_SIZE;var nodePad = Blockly.FieldMatrixCustom.THUMBNAIL_NODE_PAD;for (var i = 0; i < Blockly.FieldMatrixCustom.MATRIX_ROW; i++) {for (var n = 0; n < Blockly.FieldMatrixCustom.MATRIX_COL; n++) {var attr = {'x': ((nodeSize + nodePad) * n) + nodePad,'y': ((nodeSize + nodePad) * i) + nodePad,'width': nodeSize,'height': nodeSize,'rx': nodePad, 'ry': nodePad};this.ledThumbNodes_.push(Blockly.utils.createSvgElement('rect', attr, thumbnail));}thumbnail.style.cursor = 'default';this.updateMatrix_();}// 创建下啦箭头if (!this.arrow_) {var arrowX = this.size_.width - Blockly.BlockSvg.DROPDOWN_ARROW_PADDING * 1.5;var arrowY = (this.size_.height - Blockly.FieldMatrixCustom.ARROW_SIZE) / 2;this.arrow_ = Blockly.utils.createSvgElement('image', {'height': Blockly.FieldMatrixCustom.ARROW_SIZE + 'px','width': Blockly.FieldMatrixCustom.ARROW_SIZE + 'px','transform': 'translate(' + arrowX + ', ' + arrowY + ')'}, this.fieldGroup_);this.arrow_.setAttributeNS('http://www.w3.org/1999/xlink','xlink:href', Blockly.mainWorkspace.options.pathToMedia +'dropdown-arrow.svg');this.arrow_.style.cursor = 'default';}this.mouseDownWrapper_ = Blockly.bindEventWithChecks_(this.getClickTarget_(), 'mousedown', this, this.onMouseDown_);
};/*** 设置值* @param matrix*/
Blockly.FieldMatrixCustom.prototype.setValue = function(matrix) {if (!matrix || matrix === this.matrix_) {return;  // No change}if (this.sourceBlock_ && Blockly.Events.isEnabled()) {Blockly.Events.fire(new Blockly.Events.Change(this.sourceBlock_, 'field', this.name, this.matrix_, matrix));}matrix = matrix.padEnd(Blockly.FieldMatrixCustom.MATRIX_ROW * Blockly.FieldMatrixCustom.MATRIX_COL, "0");matrix = matrix.substr(0, Blockly.FieldMatrixCustom.MATRIX_ROW * Blockly.FieldMatrixCustom.MATRIX_COL);this.matrix_ = matrix;this.updateMatrix_();
};/*** 获取值* @returns {string}*/
Blockly.FieldMatrixCustom.prototype.getValue = function() {return String(this.matrix_);
};/*** 显示编辑器* @private*/
Blockly.FieldMatrixCustom.prototype.showEditor_ = function() {// 清除上次显示内容以及动效Blockly.DropDownDiv.hideWithoutAnimation();Blockly.DropDownDiv.clearContent();// 获取下拉内容容器var container = Blockly.DropDownDiv.getContentDiv();// 计算点阵尺寸var matrixWidth = (Blockly.FieldMatrixCustom.MATRIX_NODE_SIZE + Blockly.FieldMatrixCustom.MATRIX_NODE_PAD) *Blockly.FieldMatrixCustom.MATRIX_COL + Blockly.FieldMatrixCustom.MATRIX_NODE_PAD;var matrixHeight = (Blockly.FieldMatrixCustom.MATRIX_NODE_SIZE + Blockly.FieldMatrixCustom.MATRIX_NODE_PAD) *Blockly.FieldMatrixCustom.MATRIX_ROW + Blockly.FieldMatrixCustom.MATRIX_NODE_PAD;// 创建点阵this.matrixStage_ = Blockly.utils.createSvgElement('svg', {'xmlns': 'http://www.w3.org/2000/svg','xmlns:html': 'http://www.w3.org/1999/xhtml','xmlns:xlink': 'http://www.w3.org/1999/xlink','version': '1.1','height': matrixHeight + 'px','width': matrixWidth + 'px'}, container);// 创建点阵中的LEDthis.ledButtons_ = [];for (var i = 0; i < Blockly.FieldMatrixCustom.MATRIX_ROW; i++) {for (var n = 0; n < Blockly.FieldMatrixCustom.MATRIX_COL; n++) {var x = (Blockly.FieldMatrixCustom.MATRIX_NODE_SIZE * n) + (Blockly.FieldMatrixCustom.MATRIX_NODE_PAD * (n + 1));var y = (Blockly.FieldMatrixCustom.MATRIX_NODE_SIZE * i) + (Blockly.FieldMatrixCustom.MATRIX_NODE_PAD * (i + 1));var attr = {'x': x + 'px', 'y': y + 'px','width': Blockly.FieldMatrixCustom.MATRIX_NODE_SIZE,'height': Blockly.FieldMatrixCustom.MATRIX_NODE_SIZE,'rx': Blockly.FieldMatrixCustom.MATRIX_NODE_RADIUS,'ry': Blockly.FieldMatrixCustom.MATRIX_NODE_RADIUS};var led = Blockly.utils.createSvgElement('rect', attr, this.matrixStage_);this.matrixStage_.appendChild(led);this.ledButtons_.push(led);}}// 创建工具箱var toolbox = document.createElement('div');container.appendChild(toolbox);toolbox.className = "custom-matrix-toolbox";// led选择if (this.leds) {this.leds.innerHTML = "";} else {this.leds = document.createElement('div');}toolbox.appendChild(this.leds);this.leds.className = "custom-matrix-leds";this.leds.style.borderRight = "1px solid " + this.sourceBlock_.colourSecondary_;// 添加内置LED点阵for (var key in Blockly.FieldMatrixCustom.LEDS) {if (Blockly.FieldMatrixCustom.LEDS[key]) {this.leds.appendChild(this.createMatrixBtn_(key, Blockly.FieldMatrixCustom.LEDS[key]));}}// 添加用户LED点阵for (var key in Blockly.FieldMatrixCustom.USER) {if (Blockly.FieldMatrixCustom.USER[key]) {this.leds.appendChild(this.createMatrixBtn_(key, Blockly.FieldMatrixCustom.USER[key], true));}}// 工具var tool = document.createElement('div');toolbox.appendChild(tool);tool.className = "custom-matrix-tool";var thisField = this;// 全灭按钮var clearButtonDiv = document.createElement('div');tool.appendChild(clearButtonDiv);clearButtonDiv.innerText = "全灭";clearButtonDiv.className = "custom-matrix-btn";clearButtonDiv.onclick = function() {thisField.setValue(Blockly.FieldMatrixCustom.LEDS.ZEROS);};// 全亮按钮var fullsButtonDiv = document.createElement('div');tool.appendChild(fullsButtonDiv);fullsButtonDiv.className = "custom-matrix-btn";fullsButtonDiv.innerText = "全亮";fullsButtonDiv.onclick = function() {thisField.setValue(Blockly.FieldMatrixCustom.LEDS.FULLS);};// 保存当图案var saveButtonDiv = document.createElement('div');tool.appendChild(saveButtonDiv);saveButtonDiv.innerText = "保存";saveButtonDiv.className = "custom-matrix-btn";saveButtonDiv.onclick = function() {thisField.saveMatrix_(thisField.getValue());};Blockly.DropDownDiv.setColour(this.sourceBlock_.getColour(),this.sourceBlock_.getColourTertiary());Blockly.DropDownDiv.setCategory(this.sourceBlock_.getCategory());Blockly.DropDownDiv.showPositionedByBlock(this, this.sourceBlock_);this.matrixTouchWrapper_ = Blockly.bindEvent_(this.matrixStage_, 'mousedown', this, this.onMouseDown);this.updateMatrix_();
};/*** 创建点阵按钮*/
Blockly.FieldMatrixCustom.prototype.createMatrixBtn_ = function(key, value, enableDelete = false) {var thisField = this;var button = document.createElement('div');button.className = "custom-matrix-led-btn";button.appendChild(this.createMatrix_(value));button.value = value;button.onclick = function() {thisField.setValue(this.value);};if (enableDelete) {var removeBtn = document.createElement('div');button.appendChild(removeBtn);removeBtn.innerText = "×";removeBtn.key = key;removeBtn.className = "custom-matrix-times";removeBtn.onclick = function(e) {button.remove();thisField.removeMatrix_(this.key);e.stopPropagation();e.preventDefault();};}return button;
};/*** 创建缩略点阵*/
Blockly.FieldMatrixCustom.prototype.createMatrix_ = function(fill) {// 预览Led大小与间距var nodeSize = 4;var nodePad = 1;// 计算按钮大小var width = Blockly.FieldMatrixCustom.MATRIX_COL * (nodeSize + nodePad);var height = Blockly.FieldMatrixCustom.MATRIX_ROW * (nodeSize + nodePad);var colorEmpty = this.sourceBlock_.colourSecondary_;var colorFill = '#FFFFFF';var button = Blockly.utils.createSvgElement('svg', {'xmlns': 'http://www.w3.org/2000/svg','xmlns:html': 'http://www.w3.org/1999/xhtml','xmlns:xlink': 'http://www.w3.org/1999/xlink','version': '1.1','width': width + 'px','height': height + 'px',});for (var i = 0; i < Blockly.FieldMatrixCustom.MATRIX_ROW; i++) {for (var j = 0; j < Blockly.FieldMatrixCustom.MATRIX_COL; j++) {Blockly.utils.createSvgElement('rect', {'x': ((nodeSize + nodePad) * j) + nodePad,'y': ((nodeSize + nodePad) * i) + nodePad,'width': nodeSize,'height': nodeSize,'rx': nodePad,'ry': nodePad,'fill': (fill.charAt(Blockly.FieldMatrixCustom.MATRIX_COL * i + j) === '1') ? colorFill : colorEmpty}, button);}}return button;
};/*** 生成指定长度的随机字符串* @param len* @returns {string}*/
Blockly.FieldMatrixCustom.prototype.createRandomString = (len = 16) => {const t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678";const a = t.length;let n = "";for (let i = 0; i < len; i++) n += t.charAt(Math.floor(Math.random() * a));return n;
};/*** 保存当前点阵* @param value* @private*/
Blockly.FieldMatrixCustom.prototype.saveMatrix_ = function(value) {var key = this.createRandomString();Blockly.FieldMatrixCustom.USER[key] = value;if (this.leds) {this.leds.appendChild(this.createMatrixBtn_(key, value, true));}localStorage.setItem("USER_CUSTOM_MATRIX", JSON.stringify(Blockly.FieldMatrixCustom.USER || {}));
};/*** 移除当前点阵* @private*/
Blockly.FieldMatrixCustom.prototype.removeMatrix_ = function(key) {delete Blockly.FieldMatrixCustom.USER[key];localStorage.setItem("USER_CUSTOM_MATRIX", JSON.stringify(Blockly.FieldMatrixCustom.USER || {}));
};/*** 更新点阵* @private*/
Blockly.FieldMatrixCustom.prototype.updateMatrix_ = function() {for (var i = 0; i < this.matrix_.length; i++) {if (this.matrix_[i] === '0') {this.fillMatrixNode_(this.ledButtons_, i, this.sourceBlock_.colourSecondary_);this.fillMatrixNode_(this.ledThumbNodes_, i, this.sourceBlock_.colour_);} else {this.fillMatrixNode_(this.ledButtons_, i, '#FFFFFF');this.fillMatrixNode_(this.ledThumbNodes_, i, '#FFFFFF');}}
};Blockly.FieldMatrixCustom.prototype.fillMatrixNode_ = function(node, index, fill) {if (!node || !node[index] || !fill) return;node[index].setAttribute('fill', fill);
};Blockly.FieldMatrixCustom.prototype.setLEDNode_ = function(led, state) {if (led < 0 || led > Blockly.FieldMatrixCustom.MATRIX_COL * Blockly.FieldMatrixCustom.MATRIX_ROW - 1) return;var matrix = this.matrix_.substr(0, led) + state + this.matrix_.substr(led + 1);this.setValue(matrix);
};Blockly.FieldMatrixCustom.prototype.fillLEDNode_ = function(led) {if (led < 0 || led > Blockly.FieldMatrixCustom.MATRIX_COL * Blockly.FieldMatrixCustom.MATRIX_ROW - 1) return;this.setLEDNode_(led, '1');
};Blockly.FieldMatrixCustom.prototype.clearLEDNode_ = function(led) {if (led < 0 || led > Blockly.FieldMatrixCustom.MATRIX_COL * Blockly.FieldMatrixCustom.MATRIX_ROW - 1) return;this.setLEDNode_(led, '0');
};Blockly.FieldMatrixCustom.prototype.toggleLEDNode_ = function(led) {if (led < 0 || led > Blockly.FieldMatrixCustom.MATRIX_COL * Blockly.FieldMatrixCustom.MATRIX_ROW - 1) return;if (this.matrix_.charAt(led) === '0') {this.setLEDNode_(led, '1');} else {this.setLEDNode_(led, '0');}
};Blockly.FieldMatrixCustom.prototype.onMouseDown = function(e) {this.matrixMoveWrapper_ =Blockly.bindEvent_(document.body, 'mousemove', this, this.onMouseMove);this.matrixReleaseWrapper_ =Blockly.bindEvent_(document.body, 'mouseup', this, this.onMouseUp);var ledHit = this.checkForLED_(e);if (ledHit > -1) {if (this.matrix_.charAt(ledHit) === '0') {this.paintStyle_ = 'fill';} else {this.paintStyle_ = 'clear';}this.toggleLEDNode_(ledHit);this.updateMatrix_();} else {this.paintStyle_ = null;}
};Blockly.FieldMatrixCustom.prototype.onMouseUp = function() {Blockly.unbindEvent_(this.matrixMoveWrapper_);Blockly.unbindEvent_(this.matrixReleaseWrapper_);this.paintStyle_ = null;
};Blockly.FieldMatrixCustom.prototype.onMouseMove = function(e) {e.preventDefault();if (this.paintStyle_) {var led = this.checkForLED_(e);if (led < 0) return;if (this.paintStyle_ === 'clear') {this.clearLEDNode_(led);} else if (this.paintStyle_ === 'fill') {this.fillLEDNode_(led);}}
};Blockly.FieldMatrixCustom.prototype.checkForLED_ = function(e) {var bBox = this.matrixStage_.getBoundingClientRect();var nodeSize = Blockly.FieldMatrixCustom.MATRIX_NODE_SIZE;var nodePad = Blockly.FieldMatrixCustom.MATRIX_NODE_PAD;var dx = e.clientX - bBox.left;var dy = e.clientY - bBox.top;var min = nodePad / 2;var max = bBox.width - (nodePad / 2);if (dx < min || dx > max || dy < min || dy > max) {return -1;}var xDiv = Math.trunc((dx - nodePad / 2) / (nodeSize + nodePad));var yDiv = Math.trunc((dy - nodePad / 2) / (nodeSize + nodePad));return xDiv + (yDiv * Blockly.FieldMatrixCustom.MATRIX_COL);
};Blockly.FieldMatrixCustom.prototype.dispose_ = function() {var thisField = this;return function() {Blockly.FieldMatrixCustom.superClass_.dispose_.call(thisField)();thisField.matrixStage_ = null;if (thisField.mouseDownWrapper_) {Blockly.unbindEvent_(thisField.mouseDownWrapper_);}if (thisField.matrixTouchWrapper_) {Blockly.unbindEvent_(thisField.matrixTouchWrapper_);}if (thisField.matrixReleaseWrapper_) {Blockly.unbindEvent_(thisField.matrixReleaseWrapper_);}if (thisField.matrixMoveWrapper_) {Blockly.unbindEvent_(thisField.matrixMoveWrapper_);}};
};Blockly.Field.register('field_matrix_custom', Blockly.FieldMatrixCustom);

直接使用以上代码是不包含样式,需要额外设置CSS,CSS代码如下:

.custom-matrix-toolbox {width: 100%;position: relative;height: 105px;min-width: 200px;
}.custom-matrix-leds {height: 105px;max-height: 105px;right: 68px;overflow: auto;padding-right: 5px;margin-right: 5px;position: absolute;text-align: left;
}.custom-matrix-leds::-webkit-scrollbar {width: 0;
}.custom-matrix-times {position: absolute;top: 2px;right: 2px;width: 16px;height: 16px;text-align: center;background: rgba(0, 0, 0, .5);transition: .2s;color: white;border-radius: 8px;padding: 0;font-size: 12px;line-height: 15px;
}.custom-matrix-times:hover {background: rgba(0, 0, 0, 1);
}.custom-matrix-led-btn {display: inline-block;text-align: center;cursor: pointer;border-radius: 2px;transition: .2s;background: rgba(0, 0, 0, 0);padding: 4px 4px 0 4px;position: relative;
}.custom-matrix-led-btn:hover {background: rgba(0, 0, 0, .1);
}.custom-matrix-tool {position: absolute;right: 5px;width: 60px;
}.custom-matrix-btn {text-align: center;font-size: 12px;border-radius: 2px;cursor: pointer;transition: .2s;padding: 3px 0;color: white;margin: 0 0 5px 0;background: rgba(0, 0, 0, .1);
}.custom-matrix-btn:hover {background: rgba(0, 0, 0, .2);
}

Scratch Blocks自定义组件之「点阵」相关推荐

  1. 从 iOS 14 到 Android 12,桌面小组件是怎么「文艺复兴」的

    本文转载自 极客公园 时尚界一直以来有一个著名的理论:在某一时代流行的时尚元素,在经过一段时间的沉寂之后,会被人们再次拿出来利用. 这便是「弗莱定律」,它解释了为什么在长期的历史中,为什么很多曾经时尚 ...

  2. 用typescript完成倒计时_「干货」将数十万行CoffeeScript代码迁移到TypeScript

    作者 | David Goldstein 译者 | 王强 策划 | 小智 转发链接:https://mp.weixin.qq.com/s/TK7kWXX4hR3e-jtpVMuBnw 序言 2017 ...

  3. 怎样对流媒体进行压力测试_对node工程进行压力测试与性能分析「干货」

    作者:小黎 转发链接:https://mp.weixin.qq.com/s/WBe7ZLoqFD9UqNusnv_IDA 前言 在系统上线前,为了看下系统能承受多大的并发和并发下的负载情况,常常会先进 ...

  4. 「人造太阳」背后,能源为什么值得关注?| 极客视野

    能源大概就是人类文明的基石之一,让文明的无限进步成为可能. 圣波莱迪朗克坐落在法国南部,属于普罗旺斯地区,离同在法国南部的马赛市约 66 公里.这个鲜为人知的地方最近却受到了广泛关注,尤其是新科技爱好 ...

  5. 「Unity3D」(9)自定义编辑器菜单扩展总结

    添加菜单 [MenuItem("Tools/MyOption")] private static void MyOption() {// 自定义菜单Tools } [MenuIte ...

  6. 不挂载 组件渲染_让你的 React 组件性能跑得再快一点「实践」

    作者:天泽 转发链接:https://www.zoo.team/article/react-render 性能和渲染(Render)正相关 React 基于虚拟 DOM 和高效 Diff 算法的完美配 ...

  7. Scratch闯关游戏「离子反应」游戏规则

    请查看 Scratch闯关游戏作品:「离子反应」 下载资源. 单人游戏规则: 使用鼠标瞄准和射击,<Q>丢弃物品,<R>填充药剂,<滚轮>切换武器,<E> ...

  8. React造轮子:拖拽排序组件「Dragact」

    先来一张图看看: 项目地址:Github地址 (无耻求星!) 在线观看(第一次加载需要等几秒):预览地址 说起来不容易,人在国外没有过年一说,但是毕竟也是中国年,虽然不放假,但是家里总会主内一顿丰盛的 ...

  9. 递归循环子组件_算法一看就懂之「 递归 」

    之前的文章咱们已经聊过了 「 数组和链表 」 . 「 堆栈 」 和 「 队列 」 ,今天咱们来看看「 递归 」,当然「 递归 」并不是一种数据结构,它是很多算法都使用的一种编程方法.它太普遍了,并且用 ...

最新文章

  1. HTTP错误汇总及其解决方法
  2. 汇编语言-014(编写过程的应用、伪指令LEA、ENTER、LEAVE、LOCAL、递归函数、INVOKE、ADDR、PROC伪指令声明过程)
  3. 为何Spark更高效?
  4. C++工作笔记-3种方法对数据类型进行拆分(可用于各种协议)
  5. MySQL的chap服务器_chap01 初涉MySQL
  6. 程序员的工资普遍在20k以上
  7. LVM逻辑卷管理@设备、格式、摩、引导自己主动安装一个完整的章节
  8. kafka----kafka connect的使用(一)
  9. 【Tensorflow】【损失函数】交叉熵数据验证(下)---BinaryCrossentropy二分类
  10. 微信小程序抖音实战-支持手机播放小视频
  11. js,如何把省份简称转换成省份全称
  12. php soap header_PHP调用有SoapHeader认证的WebService实例
  13. 开发一款游戏引擎需要的知识与技术
  14. python代码画樱花教程-python画樱花树代码 具体代码介绍
  15. 拼插机器人课和围棋课_开学第一课和机器人比围棋的人是谁
  16. 数学符号的意义总结(未完待续)
  17. struts2 错误消息显示(s:fielderror )的时候老有前面的那个黑点,郁闷死了,感觉特别不爽,下面总结了集中解决的方法
  18. ConstrainLayout约束布局
  19. Node-RED使用指南:26:使用exec执行系统命令
  20. 2016百度之星 - 测试赛(热身,陈题)1001,1002,1003,1004

热门文章

  1. 学习能力 什么是真正的学习
  2. Excel文档安全性设置
  3. 后羿采集器怎么导出数据_数据采集教程_智能模式_基本操作流程_后羿采集器
  4. 使用手机远程控制电脑
  5. IOS - iPhoneX 怎么进入 DFU 模式(刷机必备)?
  6. APP性能优化--启动优化
  7. C# 面向对象-面向对象概述
  8. 自己写的wow菜鸟指南
  9. 尤雨溪的5KB petite-vue源码解析
  10. 使用计算机小窍门,电脑使用的小技巧(适用小白)