@blockly/field-bitmap
Version:
A field that lets users input a pixel grid with their mouse.
3 lines • 8.7 kB
JavaScript
/*! For license information please see index.js.LICENSE.txt */
!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e(require("blockly/core"));else if("function"==typeof define&&define.amd)define(["blockly/core"],e);else{var i="object"==typeof exports?e(require("blockly/core")):e(t.Blockly);for(var n in i)("object"==typeof exports?exports:t)[n]=i[n]}}(this,(t=>(()=>{"use strict";var e={370:e=>{e.exports=t}},i={};function n(t){var s=i[t];if(void 0!==s)return s.exports;var o=i[t]={exports:{}};return e[t](o,o.exports,n),o.exports}n.d=(t,e)=>{for(var i in e)n.o(e,i)&&!n.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:e[i]})},n.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),n.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})};var s={};n.r(s),n.d(s,{DEFAULT_HEIGHT:()=>l,DEFAULT_WIDTH:()=>r,FieldBitmap:()=>d});var o=n(370);o.Msg.BUTTON_LABEL_RANDOMIZE="Randomize",o.Msg.BUTTON_LABEL_CLEAR="Clear";const l=5,r=5,h={empty:"#fff",filled:"#363d80"},a={randomize:!0,clear:!0};class d extends o.Field{constructor(t,e,i){var n,s;super(t,e,i),this.initialValue=null,this.boundEvents=[],this.editorPixels=null,this.blockDisplayPixels=null,this.pointerIsDown=!1,this.SERIALIZABLE=!0,this.buttonOptions=Object.assign(Object.assign({},a),null==i?void 0:i.buttons),this.pixelColours=Object.assign(Object.assign({},h),null==i?void 0:i.colours);const o=this.getValue();null!==o?(this.imgHeight=o.length,this.imgWidth=o[0].length||0):(this.imgHeight=null!==(n=null==i?void 0:i.height)&&void 0!==n?n:l,this.imgWidth=null!==(s=null==i?void 0:i.width)&&void 0!==s?s:r,this.setValue(this.getEmptyArray())),this.fieldHeight=null==i?void 0:i.fieldHeight,this.fieldHeight?this.pixelSize=this.fieldHeight/this.imgHeight:this.pixelSize=15}static fromJson(t){var e;return new this(null!==(e=t.value)&&void 0!==e?e:o.Field.SKIP_SETUP,void 0,t)}getImageWidth(){return this.imgWidth}getImageHeight(){return this.imgHeight}doClassValidation_(t){if(!t)return null;if(!Array.isArray(t))return null;if(0==t.length)return null;const e=t[0].length;for(const i of t){if(!Array.isArray(i))return null;if(i.length!==e)return null}for(const e of t)for(const t of e)if(0!==t&&1!==t)return null;return t}doValueUpdate_(t){super.doValueUpdate_(t),t&&(this.imgHeight=t.length,this.imgWidth=t[0]?t[0].length:0,this.fieldHeight?this.pixelSize=this.fieldHeight/this.imgHeight:this.pixelSize=15)}showEditor_(t){const e=this.dropdownCreate();o.DropDownDiv.getContentDiv().appendChild(e),o.DropDownDiv.showPositionedByField(this,this.dropdownDispose.bind(this))}render_(){super.render_(),this.getValue()&&this.blockDisplayPixels&&this.forAllCells(((t,e)=>{const i=this.getPixel(t,e);this.blockDisplayPixels&&(this.blockDisplayPixels[t][e].style.fill=i?this.pixelColours.filled:this.pixelColours.empty),this.editorPixels&&(this.editorPixels[t][e].style.background=i?this.pixelColours.filled:this.pixelColours.empty)}))}updateEditable(){const t=super.updateEditable(),e=this.getSvgRoot();return e&&(o.utils.dom.removeClass(e,"blocklyNonEditableField"),o.utils.dom.removeClass(e,"blocklyEditableField")),t}getScaledBBox(){var t;const e=null===(t=this.getSvgRoot())||void 0===t?void 0:t.getBoundingClientRect();if(!e)throw new Error("Tried to retrieve a bounding box without a rect");return new o.utils.Rect(e.top,e.bottom,e.left,e.right)}dropdownCreate(){const t=this.createElementWithClassname("div","dropdownEditor");(this.buttonOptions.randomize||this.buttonOptions.clear)&&t.classList.add("has-buttons");const e=this.createElementWithClassname("div","pixelContainer");t.appendChild(e),o.DropDownDiv.getContentDiv().classList.add("contains-bitmap-editor"),this.bindEvent(t,"pointermove",this.onPointerMove),this.bindEvent(t,"pointerup",this.onPointerEnd),this.bindEvent(t,"pointerleave",this.onPointerEnd),this.bindEvent(t,"pointerdown",this.onPointerStart),this.bindEvent(t,"pointercancel",this.onPointerEnd),this.bindEvent(t,"touchmove",(t=>{t.preventDefault()})),this.editorPixels=[];for(let t=0;t<this.imgHeight;t++){this.editorPixels.push([]);const i=this.createElementWithClassname("div","pixelRow");for(let e=0;e<this.imgWidth;e++){const n=this.createElementWithClassname("div","pixelButton");this.editorPixels[t].push(n),i.appendChild(n);const s=this.getPixel(t,e);n.style.background=s?this.pixelColours.filled:this.pixelColours.empty,n.setAttribute("data-row",t.toString()),n.setAttribute("data-col",e.toString())}e.appendChild(i)}return this.buttonOptions.randomize&&this.addControlButton(t,o.Msg.BUTTON_LABEL_RANDOMIZE,this.randomizePixels),this.buttonOptions.clear&&this.addControlButton(t,o.Msg.BUTTON_LABEL_CLEAR,this.clearPixels),this.blockDisplayPixels&&this.forAllCells(((t,e)=>{const i=this.getPixel(t,e);this.editorPixels&&(this.editorPixels[t][e].style.background=i?this.pixelColours.filled:this.pixelColours.empty)})),this.initialValue=this.getValue(),t}initView(){this.blockDisplayPixels=[];for(let t=0;t<this.imgHeight;t++){const e=[];for(let i=0;i<this.imgWidth;i++){const n=o.utils.dom.createSvgElement("rect",{x:i*this.pixelSize,y:t*this.pixelSize,width:this.pixelSize,height:this.pixelSize,fill:this.pixelColours.empty,fill_opacity:1},this.getSvgRoot());e.push(n)}this.blockDisplayPixels.push(e)}}updateSize_(){{const t=this.pixelSize*this.imgWidth,e=this.pixelSize*this.imgHeight;this.borderRect_&&(this.borderRect_.setAttribute("width",String(t)),this.borderRect_.setAttribute("height",String(e))),this.size_.width=t,this.size_.height=e}}addControlButton(t,e,i){const n=this.createElementWithClassname("button","controlButton");n.innerText=e,t.appendChild(n),this.bindEvent(n,"click",i)}dropdownDispose(){this.getSourceBlock()&&null!==this.initialValue&&this.initialValue!==this.getValue()&&o.Events.fire(new(o.Events.get(o.Events.BLOCK_CHANGE))(this.sourceBlock_,"field",this.name||null,this.initialValue,this.getValue()));for(const t of this.boundEvents)o.browserEvents.unbind(t);this.boundEvents.length=0,this.editorPixels=null,this.initialValue=null,o.DropDownDiv.getContentDiv().classList.remove("contains-bitmap-editor")}getEmptyArray(){const t=[];for(let e=0;e<this.imgHeight;e++){t.push([]);for(let i=0;i<this.imgWidth;i++)t[e].push(0)}return t}onPointerStart(t){const e=document.elementFromPoint(t.clientX,t.clientY),i=null==e?void 0:e.getAttribute("data-row"),n=null==e?void 0:e.getAttribute("data-col");i&&n&&(this.onPointerDownInPixel(parseInt(i),parseInt(n)),this.pointerIsDown=!0,t.preventDefault())}onPointerMove(t){if(!this.pointerIsDown)return;const e=document.elementFromPoint(t.clientX,t.clientY),i=null==e?void 0:e.getAttribute("data-row"),n=null==e?void 0:e.getAttribute("data-col");i&&n&&this.updatePixelValue(parseInt(i),parseInt(n)),t.preventDefault()}onPointerDownInPixel(t,e){const i=1-this.getPixel(t,e);this.setPixel(t,e,i),this.pointerIsDown=!0,this.valToPaintWith=i}updatePixelValue(t,e){void 0!==this.valToPaintWith&&this.getPixel(t,e)!==this.valToPaintWith&&this.setPixel(t,e,this.valToPaintWith)}onPointerEnd(){this.pointerIsDown=!1,this.valToPaintWith=void 0}randomizePixels(){this.forAllCells(((t,e)=>{this.setPixel(t,e,Math.floor(2*Math.random()))}))}clearPixels(){const t=this.getEmptyArray();this.fireIntermediateChangeEvent(t),this.setValue(t,!1)}setPixel(t,e,i){const n=JSON.parse(JSON.stringify(this.getValue()));n[t][e]=i,this.fireIntermediateChangeEvent(n),this.setValue(n,!1)}getPixel(t,e){const i=this.getValue();if(!i)throw new Error("Attempted to retrieve a pixel value when no value is set");return i[t][e]}forAllCells(t){for(let e=0;e<this.imgHeight;e++)for(let i=0;i<this.imgWidth;i++)t(e,i)}createElementWithClassname(t,e){const i=document.createElement(t);return i.className=e,i}bindEvent(t,e,i){this.boundEvents.push(o.browserEvents.bind(t,e,this,i))}fireIntermediateChangeEvent(t){this.getSourceBlock()&&o.Events.fire(new(o.Events.get(o.Events.BLOCK_FIELD_INTERMEDIATE_CHANGE))(this.getSourceBlock(),this.name||null,this.getValue(),t))}}return o.fieldRegistry.register("field_bitmap",d),o.Css.register("\n.dropdownEditor {\n align-items: center;\n flex-direction: column;\n display: flex;\n justify-content: center;\n}\n.dropdownEditor.has-buttons {\n margin-bottom: 20px;\n}\n.pixelContainer {\n margin: 20px;\n}\n.pixelRow {\n display: flex;\n flex-direction: row;\n padding: 0;\n margin: 0;\n height: 15\n}\n.pixelButton {\n width: 15px;\n height: 15px;\n border: 1px solid #000;\n}\n.pixelDisplay {\n white-space:pre-wrap;\n}\n.controlButton {\n margin: 5px 0;\n}\n.blocklyDropDownContent.contains-bitmap-editor {\n max-height: none;\n}\n"),s})()));
//# sourceMappingURL=index.js.map