User Tools

Site Tools


konvabean

This is an old revision of the document!


MIStudio Konva Bean

TL;DR / Quick Start

See the end of the document for a prompt ready for your favorite LLM - ChatGPT, CoPilot, Claude, Gemini, etc.

Three critical rules

  • Use class-body method syntax:
init(container) {

NOT:

function init(container) {
  • Handle incoming values in:
updateValues(incomingValue) {
  • Incoming values are normally JSON. Parse:
var obj = JSON.parse(incomingValue);

then, for example, get the float value:

var value = parseFloat(obj.value);

Small Working Example

Paste this directly into the InitJavaScript property of a Konva bean.

init(container) {
  container.innerHTML = "";
 
  this.stage = new window.Konva.Stage({
    container: container,
    width: container.clientWidth || 300,
    height: container.clientHeight || 200
  });
 
  this.layer = new window.Konva.Layer();
  this.stage.add(this.layer);
 
  this.circle = new window.Konva.Circle({
    x: 100,
    y: 100,
    radius: 40,
    fill: "steelblue"
  });
 
  this.layer.add(this.circle);
  this.layer.draw();
}
 
updateValues(incomingValue) {
  try {
    var obj = JSON.parse(incomingValue);
    var value = parseFloat(obj.value);
 
    this.circle.fill(value > 50 ? "red" : "green");
    this.layer.draw();
  } catch (err) {
    console.error(err);
  }
}

How the Konva Bean Works

The Konva Bean wraps your JavaScript inside a generated JavaScript class.

Your code is inserted inside a class body. Therefore you must write JavaScript methods using class syntax.

Valid:

init(container) {
}
 
updateValues(incomingValue) {
}
 
cleanup() {
}

Invalid:

function init(container) {
}
 
const init = () => {
}

Bean Lifecycle

init(container)

Called when the component is created.

Use it to:

  • Create Konva stage/layers
  • Create shapes
  • Start animations
  • Configure resize handling

updateValues(incomingValue)

Called whenever the bean receives data.

Typically receives JSON like:

{
  "value":71,
  "timestamp":1779727392926,
  "valueType":73,
  "alwaysSend":false,
  "quality":0,
  "properties":{"ORDER":0}
}

Typical parsing:

var obj = JSON.parse(incomingValue);
var value = parseFloat(obj.value);

cleanup()

Optional cleanup hook called before script reload.

Use it to:

  • Stop animations
  • Disconnect ResizeObservers
  • Destroy Konva stages
  • Remove listeners

Full Responsive Example

This example:

  • Respects MIStudio bean bounds
  • Automatically resizes
  • Clips to container
  • Parses incoming JSON
  • Changes ball size/color/speed
init(container) {
  container.innerHTML = "";
  container.style.overflow = "hidden";
  container.style.position = "relative";
 
  if (typeof window.Konva === "undefined") {
    container.innerHTML = "Konva is NOT loaded";
    return;
  }
 
  this.stageHost = document.createElement("div");
  this.stageHost.style.position = "absolute";
  this.stageHost.style.left = "0px";
  this.stageHost.style.top = "0px";
  this.stageHost.style.overflow = "hidden";
  container.appendChild(this.stageHost);
 
  var w = container.clientWidth || 400;
  var h = container.clientHeight || 300;
 
  this.stage = new window.Konva.Stage({
    container: this.stageHost,
    width: w,
    height: h
  });
 
  this.layer = new window.Konva.Layer();
  this.stage.add(this.layer);
 
  this.circle = new window.Konva.Circle({
    x: 60,
    y: h / 2,
    radius: 35,
    fill: "steelblue",
    stroke: "white",
    strokeWidth: 2
  });
 
  this.layer.add(this.circle);
 
  var direction = 1;
  var self = this;
 
  this.resize = function() {
    var w = container.clientWidth || 1;
    var h = container.clientHeight || 1;
 
    self.stage.width(w);
    self.stage.height(h);
 
    self.circle.y(h / 2);
 
    var r = self.circle.radius();
    self.circle.x(Math.max(r, Math.min(w - r, self.circle.x())));
 
    self.layer.draw();
  };
 
  this.resizeObserver = new ResizeObserver(function() {
    self.resize();
  });
 
  this.resizeObserver.observe(container);
 
  this.anim = new window.Konva.Animation(function(frame) {
    var speed = self.speed || 100;
    var dt = frame && frame.timeDiff ? frame.timeDiff : 16;
    var r = self.circle.radius();
    var w = self.stage.width();
 
    var x = self.circle.x() + direction * speed * dt / 1000;
 
    if (x > w - r) {
      x = w - r;
      direction = -1;
    }
 
    if (x < r) {
      x = r;
      direction = 1;
    }
 
    self.circle.x(x);
  }, this.layer);
 
  this.anim.start();
}
 
cleanup() {
  if (this.resizeObserver) {
    this.resizeObserver.disconnect();
    this.resizeObserver = null;
  }
 
  if (this.anim) {
    this.anim.stop();
    this.anim = null;
  }
 
  if (this.stage) {
    this.stage.destroy();
    this.stage = null;
  }
}
 
updateValues(incomingValue) {
  var value = NaN;
 
  try {
    var obj = JSON.parse(incomingValue);
    value = parseFloat(obj.value);
  } catch (err) {
    value = parseFloat(incomingValue);
  }
 
  if (!isNaN(value) && this.circle) {
    this.circle.radius(Math.max(10, Math.min(100, value)));
 
    if (value < 30) {
      this.circle.fill("green");
    } else if (value < 70) {
      this.circle.fill("orange");
    } else {
      this.circle.fill("red");
    }
 
    this.speed = Math.max(20, value * 3);
 
    if (this.resize) {
      this.resize();
    }
 
    this.layer.draw();
  }
}

Troubleshooting

Unexpected token '{'

You likely used:

function init(container) {

Instead of:

init(container) {

Cannot read properties of undefined (reading 'init')

Usually means the generated instance was not created or the script had a syntax error.

Konva is NOT loaded

Ensure:

scriptSources = "konva.min.js"

LLM Meta Prompt

Copy this into ChatGPT/Claude/etc. and describe the visualization you want.

Generate JavaScript for an MIStudio Konva Bean.

CRITICAL REQUIREMENTS:

1. Use class-body method syntax only:
init(container) { }
updateValues(incomingValue) { }
cleanup() { }

DO NOT generate:
function init() { }
top-level JavaScript
arrow functions for lifecycle methods

2. Use window.Konva.

3. Respect container bounds.
Use ResizeObserver and resize with container changes.

4. Use cleanup() to stop animations, disconnect observers and destroy Konva resources.

5. updateValues(incomingValue) receives JSON:
{
  "value": number,
  "timestamp": number,
  "valueType": number,
  "quality": number
}

Parse with:
var obj = JSON.parse(incomingValue);
var value = parseFloat(obj.value);

6. Use this.<property> for state.

7. Graphics must stay inside the bean bounds.

8. Use Konva animations and industrial-style visuals suitable for manufacturing (robots, conveyors, tanks, gauges, wafer maps, valves, alarms, etc.).

Now generate a complete working MIStudio Konva Bean for:
[DESCRIBE YOUR GRAPHIC HERE]
konvabean.1779751308.txt.gz · Last modified: by wikiadmin

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki