Widget:ConvertCalc2: Difference between revisions

From WyrdeWiki
No edit summary
mNo edit summary
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
<noinclude>__NOTOC__
<noinclude>__NOTOC__
This is a universal two-unit converter widget using a single slider.
This widget converts between two units with a single slider.


=Usage=
=Usage=
{{#widget:ConvertCalc2
{{#widget:ConvertCalc2
| id=cc1
  | TopLabel=years
  | TopLabel=Years
  | TopFactor=1.3125
  | TopFactor=1.3125
  | BottomLabel=Cycles
  | BottomLabel=Cycles
Line 14: Line 13:
}}
}}
{| class="wikitable"
{| class="wikitable"
|-
! param !! meaning !! default
! param !! meaning !! default
|-
|-
| TopLabel || text label at the top || years
| TopLabel || name shown for the top value || years
|-
|-
| TopFactor || multiplicative factor for the top value || 1.3125
| TopFactor || factor for 1 Top unit (used in bottom = top * Bottom/Top) || 1.3125
|-
|-
| BottomLabel || text label at the bottom || Cycles
| BottomLabel || name shown for the bottom value || Cycles
|-
|-
| BottomFactor || multiplicative factor for the bottom value || 1
| BottomFactor || factor for 1 Bottom unit || 1
|-
|-
| SliderMin || minimum value N || 1
| SliderMin || minimum slider value (top value) || 1
|-
|-
| SliderMax || maximum value N || 100
| SliderMax || maximum slider value (top value) || 100
|-
|-
| SliderStep || slider step || 0.1
| SliderStep || slider step || 0.1
|}
|}
</noinclude><includeonly>
</noinclude><includeonly>
<div class="wh-convertcalc2" style="max-width:720px;margin:1rem 0;">
  <!-- Top title (Capitalized) -->
  <div id="cc2-title-top" style="font-weight:700;margin-bottom:.35rem;text-transform:capitalize;">years</div>


<div class="wh-convertcalc2" style="width:768px;margin:1rem 0;">
  <!-- Top value centered above slider -->
  <strong><!--{$TopLabel|default:'years'|escape:'html'}--></strong>
  <div style="display:flex;justify-content:center;margin-bottom:.4rem;">
    <input id="cc2-topval" type="number" step="0.01" style="width:10ch;text-align:right;margin-right:.4rem;">
    <span id="cc2-toplabel">years</span>
  </div>


   <div id="<!--{$id|default:'cc'|escape:'html'}-->-topval"
   <!-- Slider row with swap on the right -->
      style="text-align:center;margin:.3rem 0;font-size:1.3rem;font-weight:600;">
  <div style="display:flex;align-items:center;gap:.6rem;">
    —
    <input id="cc2-slider" type="range" style="flex:1;">
    <button id="cc2-swap" title="Swap units" style="font-size:1rem;line-height:1;padding:.25rem .45rem;cursor:pointer;">⇅</button>
   </div>
   </div>


   <input id="<!--{$id|default:'cc'|escape:'html'}-->-slider"
   <!-- Bottom value centered below slider -->
        type="range"
  <div style="display:flex;justify-content:center;margin:.5rem 0 .6rem;">
        min="<!--{$SliderMin|default:1|escape:'html'}-->"
    <input id="cc2-botval" type="number" step="0.01" style="width:10ch;text-align:right;margin-right:.4rem;" readonly>
        max="<!--{$SliderMax|default:100|escape:'html'}-->"
     <span id="cc2-botlabel">Cycles</span>
        step="<!--{$SliderStep|default:0.1|escape:'html'}-->"
        value="<!--{$SliderMin|default:1|escape:'html'}-->"
        style="width:100%;">
 
  <div id="<!--{$id|default:'cc'|escape:'html'}-->-botval"
      style="text-align:center;margin:.3rem 0;font-size:1.3rem;font-weight:600;">
     —
   </div>
   </div>


   <strong><!--{$BottomLabel|default:'Cycles'|escape:'html'}--></strong>
   <!-- Bottom title (Capitalized) -->
  <div id="cc2-title-bot" style="font-weight:700;text-transform:capitalize;">Cycles</div>
</div>
</div>


<script type="text/javascript">
<script type="text/javascript">
(function(){
(function(){
   var ID = "<!--{$id|default:'cc'|escape:'js'}-->";
  // Pull parameters (only the ones you defined)
   function ge(s){ return document.getElementById(ID + s); }
  var TopLabel    = "<!--{$TopLabel|default:'years'|escape:'js'}-->";
  var TopFactor    = parseFloat("<!--{$TopFactor|default:1.3125|escape:'js'}-->") || 1.3125;
  var BottomLabel  = "<!--{$BottomLabel|default:'Cycles'|escape:'js'}-->";
  var BottomFactor = parseFloat("<!--{$BottomFactor|default:1|escape:'js'}-->") || 1;
 
  var SL_MIN  = parseFloat("<!--{$SliderMin|default:1|escape:'js'}-->")  || 1;
   var SL_MAX  = parseFloat("<!--{$SliderMax|default:100|escape:'js'}-->") || 100;
  var SL_STEP  = parseFloat("<!--{$SliderStep|default:0.1|escape:'js'}-->") || 0.1;
 
  // Simple helpers
   function ge(id){ return document.getElementById(id); }
  function cap(s){ return (s||'').slice(0,1).toUpperCase() + (s||'').slice(1); }
  function fix2(n){ return (Math.round(n*100)/100).toFixed(2); }
  function clamp(x,a,b){ return Math.min(b, Math.max(a, x)); }


   var TopLabel  = "<!--{$TopLabel|default:'years'|escape:'js'}-->";
  // Elements
   var TopFactor  = parseFloat("<!--{$TopFactor|default:1.3125|escape:'js'}-->");
   var eTopTitle = ge("cc2-title-top");
   var BottomLabel= "<!--{$BottomLabel|default:'Cycles'|escape:'js'}-->";
  var eBotTitle = ge("cc2-title-bot");
   var BottomFactor=parseFloat("<!--{$BottomFactor|default:1|escape:'js'}-->");
   var eTopLbl  = ge("cc2-toplabel");
    
   var eBotLbl  = ge("cc2-botlabel");
   function fmt(x){
   var eTopVal  = ge("cc2-topval");
    if(x >= 1000) return x.toLocaleString();
   var eBotVal   = ge("cc2-botval");
     return x.toFixed(2).replace(/\.00$/,'');
  var eSlider  = ge("cc2-slider");
  }
  var eSwap     = ge("cc2-swap");


   function ready(fn){
  // Init labels/titles
     if(document.readyState === "complete" || document.readyState === "interactive"){
   function paintLabels(){
      setTimeout(fn,0);
     eTopTitle.textContent = cap(TopLabel);
     } else {
    eBotTitle.textContent = cap(BottomLabel);
      document.addEventListener("DOMContentLoaded", fn, {once:true});
     eTopLbl.textContent  = TopLabel;
     }
     eBotLbl.textContent  = BottomLabel;
   }
   }
  paintLabels();


   ready(function init(){
   // Slider config (slider always controls TOP value)
    var slider = ge("-slider");
  eSlider.min  = SL_MIN;
    var topval = ge("-topval");
  eSlider.max  = SL_MAX;
    var botval = ge("-botval");
  eSlider.step = SL_STEP;
  eSlider.value = SL_MIN;


    if(!slider || !topval || !botval) return;
  // Set initial numbers
  eTopVal.value = fix2(parseFloat(eSlider.value));
  eBotVal.value = fix2(parseFloat(eTopVal.value) * (BottomFactor / TopFactor));


    function update(){
  // Update cascade from top value (slider or manual input)
      var N = parseFloat(slider.value) || 0;
  function fromTop(v){
    var topNum = clamp(parseFloat(v)||0, SL_MIN, SL_MAX);
    eSlider.value = topNum;
    eTopVal.value = fix2(topNum);
    var bottom = topNum * (BottomFactor / TopFactor);
    eBotVal.value = fix2(bottom);
  }


      topval.textContent = fmt(N * TopFactor) + " " + TopLabel;
  // Events
      botval.textContent = fmt(N * BottomFactor) + " " + BottomLabel;
  eSlider.addEventListener("input", function(){ fromTop(this.value); });
    }
  eTopVal.addEventListener("input", function(){ fromTop(this.value); });


    slider.addEventListener("input", update);
  // Swap button: swap labels & factors; slider still drives TOP
     update();
  eSwap.addEventListener("click", function(){
    var tl = TopLabel; TopLabel = BottomLabel; BottomLabel = tl;
    var tf = TopFactor; TopFactor = BottomFactor; BottomFactor = tf;
    paintLabels();
     // keep same numeric top value; just recompute bottom
    fromTop(eTopVal.value);
   });
   });
})();
})();
</script>
</script>
</includeonly>
</includeonly>

Latest revision as of 23:35, 11 November 2025

This widget converts between two units with a single slider.

Usage

years
years
Cycles
Cycles

param meaning default
TopLabel name shown for the top value years
TopFactor factor for 1 Top unit (used in bottom = top * Bottom/Top) 1.3125
BottomLabel name shown for the bottom value Cycles
BottomFactor factor for 1 Bottom unit 1
SliderMin minimum slider value (top value) 1
SliderMax maximum slider value (top value) 100
SliderStep slider step 0.1