Adding images dynamically

285 views
Skip to first unread message

Chung WONG

unread,
Apr 20, 2021, 1:20:31 AM4/20/21
to Blockly
Hi All,

I am trying to define a block

```javascript
Blockly.defineBlocksWithJsonArray([
  {
    "type": "variables_get_dynamic",
    "message0": "%1 %2",
    "args0": [
      {
        "type": "field_variable",
        "name": "VAR",
        "variable": "%{BKY_VARIABLES_DEFAULT_NAME}"
      },
      {
        "type": "field_image",
        "width": 15,
        "height": 15,
        "alt": "*"
      }
    ],
    "output": null,
    "mutator": "my_mutator"
  },
]);
```

The initial `src` for `field_image` is unknown(src has to be empty/null at the beginning) so I cannot use the above definition.
So I ended up using

```javascript
Blockly.defineBlocksWithJsonArray([
  {
    "type": "variables_get_dynamic",
    "message0": "%1",
    "args0": [
      {
        "type": "field_variable",
        "name": "VAR",
        "variable": "%{BKY_VARIABLES_DEFAULT_NAME}"
      }
    ],
    "output": null,
    "mutator": "my_mutator"
  },
]);
(Blockly as any).Constants.VariablesDynamic.MY_MUTATOR = {
  mutationToDom: function() {
    const container: Element = Blockly.utils.xml.createElement('mutation');
    const image: string = this.data;
    setImage(this, image);

    container.setAttribute('image', image);
    return container;
  },
  domToMutation: function(xmlElement: Element) {
  },
};
const setImage = (block: Blockly.BlockSvg, image: string) => {
  if (image) {
    const name: string = block.getField('VAR').getText();
    const currentImage: string = block.getField('IMAGE');
    const imgSrc = 'some_img_src';

    if (!imgSrc) {
      return;
    }

      block
      .appendDummyInput()
      .appendField(new Blockly.FieldImage(imgSrc, 35, 35, "*"), 'IMAGE')
  }
};
```

The image displayed fine but dragging the block will throw errors
```
blockly_compressed.js?e98f:319 Uncaught TypeError: Cannot read property 'fieldRow' of undefined
    at Blockly.InsertionMarkerManager.createMarkerBlock_ (blockly_compressed.js?e98f:319)
    at new Blockly.InsertionMarkerManager (blockly_compressed.js?e98f:314)
    at new Blockly.BlockDragger (blockly_compressed.js?e98f:333)
    at Blockly.TouchGesture.Blockly.Gesture.startDraggingBlock_ (blockly_compressed.js?e98f:436)
    at Blockly.TouchGesture.Blockly.Gesture.updateIsDraggingBlock_ (blockly_compressed.js?e98f:433)
    at Blockly.TouchGesture.Blockly.Gesture.updateIsDragging_ (blockly_compressed.js?e98f:435)
    at Blockly.TouchGesture.Blockly.Gesture.updateFromEvent_ (blockly_compressed.js?e98f:430)
    at Blockly.TouchGesture.Blockly.Gesture.handleMove (blockly_compressed.js?e98f:441)
    at Blockly.TouchGesture.handleMove (blockly_compressed.js?e98f:677)
    at HTMLDocument.h (blockly_compressed.js?e98f:57)
Blockly.InsertionMarkerManager.createMarkerBlock_ @ blockly_compressed.js?e98f:319
Blockly.InsertionMarkerManager @ blockly_compressed.js?e98f:314
Blockly.BlockDragger @ blockly_compressed.js?e98f:333
Blockly.Gesture.startDraggingBlock_ @ blockly_compressed.js?e98f:436
Blockly.Gesture.updateIsDraggingBlock_ @ blockly_compressed.js?e98f:433
Blockly.Gesture.updateIsDragging_ @ blockly_compressed.js?e98f:435
Blockly.Gesture.updateFromEvent_ @ blockly_compressed.js?e98f:430
Blockly.Gesture.handleMove @ blockly_compressed.js?e98f:441
Blockly.TouchGesture.handleMove @ blockly_compressed.js?e98f:677
h @ blockly_compressed.js?e98f:57


8blockly_compressed.js?e98f:441 Uncaught TypeError: Cannot read property 'dragBlock' of null
    at Blockly.TouchGesture.Blockly.Gesture.handleMove (blockly_compressed.js?e98f:441)
    at Blockly.TouchGesture.handleMove (blockly_compressed.js?e98f:677)
    at HTMLDocument.h (blockly_compressed.js?e98f:57)
Blockly.Gesture.handleMove @ blockly_compressed.js?e98f:441
Blockly.TouchGesture.handleMove @ blockly_compressed.js?e98f:677
h @ blockly_compressed.js?e98f:57


blockly_compressed.js?e98f:442 Uncaught TypeError: Cannot read property 'endBlockDrag' of null
    at Blockly.TouchGesture.Blockly.Gesture.handleUp (blockly_compressed.js?e98f:442)
    at Blockly.TouchGesture.handleUp (blockly_compressed.js?e98f:678)
    at HTMLDocument.h (blockly_compressed.js?e98f:57)
``

I am guessing I could be either missing something in the mutation or adding the image field incorrectly. 


Beka Westberg

unread,
Apr 20, 2021, 6:55:01 PM4/20/21
to blo...@googlegroups.com
Hello,

This is "caused" by issue #4485. Basically, you just need to define your domToMutation method. That way the InsertionMarkerManager can properly create new blocks =)

Best wishes,
Beka

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/fb2341f8-b98e-4511-a7ee-b37519836923n%40googlegroups.com.

Chung WONG

unread,
Apr 20, 2021, 10:26:24 PM4/20/21
to Blockly
Hi Beka,

I do have domToMutation  in my mutator, although it is not donig anything  domToMutation: function(xmlElement: Element) {}
From issue 4485,  you mentioned about domToMutation method is not properly defined. What is regard as properly properly defined. I know a mutator requires both mutationToDom and domToMutation, but I couldn't see the spec mentions about the required implementation of domToMutation.

Beka Westberg

unread,
Apr 20, 2021, 11:16:13 PM4/20/21
to blo...@googlegroups.com
Oh yeah sorry! By "properly defined" it means that you need to make sure that your domToMutation function takes in the XML and then modifies the block to match what it says. So in your case you'd need to take the 'image' attribute from the mutation element, and then pass that (along with your block) to your setImage function =)

You're basically doing round-trip serialization. mutationToDom serializes the state of the block to XML, and then domToMutation takes that saved data and modifies the block's state to match.

Best wishes,
Beka

Reply all
Reply to author
Forward
0 new messages