Skip to main content

Dynamic gauge

An example of advanced decoration, which supports changing data

Download original notebook

Define

gauge /: MakeBoxes[g_gauge, StandardForm] := ViewBox[g, g]

Now we need to implement the interpretation function on the frontend

.js

core.gauge = async (args, env) => {
  
  // Create a gauge meter element
  const gauge = document.createElement('div');
  gauge.style.width = '100px'; // half the original width
  gauge.style.height = '50px'; // half the original height
  gauge.style.border = '1px solid #000';
  gauge.style.borderRadius = '50px 50px 0 0'; // adjusted for smaller size
  gauge.style.position = 'relative';
  gauge.style.background = 'linear-gradient(to right, red 0%, yellow 50%, green 100%)';

  // Create a needle for the gauge
  const needle = document.createElement('div');
  needle.style.width = '2px';
  needle.style.height = '40px'; // made the needle longer for better visibility
  needle.style.background = '#000';
  needle.style.position = 'absolute';
  needle.style.bottom = '0';
  needle.style.left = '50%';
  needle.style.transformOrigin = 'bottom';

  // Function to set the needle position based on input value
  function setNeedlePosition(value) {
    // Ensure value is between 0 and 1
    value = Math.max(0, Math.min(1, value));
    // Convert value to angle
    const angle = value * 180 - 90; // -90 to 90 degrees
    needle.style.transform = `rotate(${angle}deg)`;
  }

  // Set initial needle position
  const pos = await interpretate(args[0], env);
  setNeedlePosition(pos); // Middle position
  

  gauge.appendChild(needle);

  env.element.appendChild(gauge);
  env.local.update = setNeedlePosition;
}

core.gauge.update = async (args, env) => {
  const val = await interpretate(args[0], env);
  env.local.update(val);
}

core.gauge.destroy = () => {
  console.log('Nothing to do');
}

core.gauge.virtual = true;

core.gauge = async (args, env) => {
  
  // Create a gauge meter element
  const gauge = document.createElement('div');
  gauge.style.width = '100px'; // half the original width
  gauge.style.height = '50px'; // half the original height
  gauge.style.border = '1px solid #000';
  gauge.style.borderRadius = '50px 50px 0 0'; // adjusted for smaller size
  gauge.style.position = 'relative';
  gauge.style.background = 'linear-gradient(to right, red 0%, yellow 50%, green 100%)';

  // Create a needle for the gauge
  const needle = document.createElement('div');
  needle.style.width = '2px';
  needle.style.height = '40px'; // made the needle longer for better visibility
  needle.style.background = '#000';
  needle.style.position = 'absolute';
  needle.style.bottom = '0';
  needle.style.left = '50%';
  needle.style.transformOrigin = 'bottom';

  // Function to set the needle position based on input value
  function setNeedlePosition(value) {
    // Ensure value is between 0 and 1
    value = Math.max(0, Math.min(1, value));
    // Convert value to angle
    const angle = value * 180 - 90; // -90 to 90 degrees
    needle.style.transform = `rotate(${angle}deg)`;
  }

  // Set initial needle position
  const pos = await interpretate(args[0], env);
  setNeedlePosition(pos); // Middle position
  

  gauge.appendChild(needle);

  env.element.appendChild(gauge);
  env.local.update = setNeedlePosition;
}

core.gauge.update = async (args, env) => {
  const val = await interpretate(args[0], env);
  env.local.update(val);
}

core.gauge.destroy = () => {
  console.log('Nothing to do');
}

core.gauge.virtual = true;

Let us test it!

gauge[0.3]
(*VB[*)(gauge[0.3])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRAeK5BITyxNTy0yBoPL9gCxdwlI"*)(*]VB*)

Dynamics

gvalue = 0.1;
EventHandler[InputRange[0, 1, 0.1, 0.1], (gvalue = #) &]

gauge[gvalue // Offload]
(*VB[*)(EventObject[<|"Id" -> "779cc45c-7931-400c-a30b-10b1478d8fbd", "Initial" -> 0.1, "View" -> "43a61dc6-e46a-46ab-a0e1-140f93d421a9"|>])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRCeEJBwK8rPK3HNS3GtSE0uLUlMykkNVgEKmxgnmhmmJJvpppqYJeoCcZJuokGqoa6hiUGapXGKiZFhoiUAhbUVjw=="*)(*]VB*)
(*VB[*)(gauge[Offload[gvalue]])(*,*)(*"1:eJxTTMoPSmNkYGAoZgESHvk5KRAeK5BITyxNT4Vw2YGEf1paTn5iSjEbSKosMac0FQBuxw0r"*)(*]VB*)