0

我正在尝试组合一个 GUI 来设置一些定价。
需要以图形方式表示三个类别,以及我们希望使用两个滑块来设置建议的买入/卖出价格。

作为练习,我拼凑了一些原型并将它们放在 jsFiddle 上
请快速看一下,它会比我的话更有效地解释它: )
(请原谅我的 JS ......还没有重构它)

因为我们的目标是让滑块在 HTML 输入中设置浮动,所以我倾向于 SVG。

  1. 我的第一个请求只是对我选择的 SVG 解决方案进行同行评审......只是想确保我不会遇到一些固有的和痛苦的障碍。我也愿意接受其他解决方案的争论。
  2. 其次是一个问题。有没有人有任何好的链接/示例可以帮助我了解如何根据形状的位置设置输入值?

(我预计该位置将代表定义的 $$ 范围的百分比,因此我们可以推断出特定的 $$ 值)

非常感谢任何和所有帮助。

4

1 回答 1

0

这是我制作的一个演示,它使用 SVG 设置四个输入,反之亦然: http:
//phrogz.net/svg/complex-plane-picker.xhtml

前两个输入是 X 和 Y(实数和复数分量);底部两个是极坐标(大小和角度)。

那里的代码可能比您需要的要多(靠近边缘/中间时自动缩放,绘制更新的轴刻度),这可能会使它作为演示更令人困惑而不是有用。

不过,一般来说,您需要:

  • keyup在输入的or changeor事件上有一个事件侦听input器,并相应地更新 SVG 以匹配。
  • 将拖动添加到您的 SVG 元素,并在拖动期间计算适当的值并相应地设置.value输入。

作为提示,在拖动过程中不要尝试检测mousemove您的可拖动元素本身。如果鼠标移到此之外,您将停止获得拖动事件并且它不会跟上。相反,我通常使用这个逻辑:

  • mousedown
    1. 记录当前光标位置
    2. 在文档的根目录上注册一个mousemove处理程序
    3. 在文档的根目录上注册一个mouseup处理程序
  • mousemove
    1. 检测当前光标位置和拖动开始位置之间的屏幕空间增量,并使用它来计算被拖动元素的本地空间中的增量以更新其变换。
  • mouseup
    1. 取消注册mousemove处理程序。

这是完整的源代码,万一我的网站关闭了:

<!DOCTYPE HTML>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"><head> 
  <meta http-equiv="content-type" content="application/xhtml+xml; charset=utf-8" />
  <title>SVG Complex Plane Input</title>
  <style type="text/css" media="screen">
    html, body { background:#eee; margin:0 }
    p { margin:0.5em; text-align:center }
    .complex-plane-picker svg { width:200px; height:200px; display:block; margin:1em auto; stroke-linejoin:round; stroke-linecap:round; pointer-events:all; }
    .complex-plane-picker rect.bg { fill:#fff; }
    .complex-plane-picker .axes * { stroke:#ccc; fill:none }
    .complex-plane-picker .dot { fill:#090; fill-opacity:0.4; stroke:#000; stroke-opacity:0.6; cursor:move; }
    .complex-plane-picker input { width:6em; }
    .complex-plane-picker .labels { stroke:none; font-size:6px; font-family:'Verdana'; text-anchor:middle; alignment-baseline:middle; }
    .complex-plane-picker .scalers { pointer-events:all; }
  </style>
</head><body>
<p>Drag the dot to set the complex value.<br/> TODO: Hold down shift to affect only the magnitude. Hold down alt to affect only the angle. Hold down both to snap to the nearest real- or imaginary-only value.</p>
<div class="complex-plane-picker">
  <p class="rectangular"><input type="number" value="0" class='real' />+<input type="number" value="0" class='imaginary' />i</p>
  <svg viewBox="-50 -50 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full">
    <rect class="bg" x="-50" y="-50" width="100" height="100" />
    <g class="scalers">
      <rect x="-5" y="-5" width="10" height="10" fill="#ffc"/>
      <rect x="-45" y="-45" width="90" height="90" fill="none" stroke="#ffc" stroke-width="10" />
    </g>
    <g class="axes">
      <g>
        <line x1="-49" y1="0" x2="49" y2="0" />
        <polyline points="-44,5 -49,0 -44,-5" />
        <polyline points="44,5 49,0 44,-5" />
      </g>
      <g transform="rotate(90)">
        <line x1="-49" y1="0" x2="49" y2="0" />
        <polyline points="-44,5 -49,0 -44,-5" />
        <polyline points="44,5 49,0 44,-5" />
      </g>
    </g>
    <g class="labels" id="labels">
      <text x="0" y="0">0</text>
      <text x="0" y="0">0</text>
      <text x="0" y="0">0</text>
      <text x="0" y="0">0</text>
    </g>
    <use class="labels" xlink:href="#labels" transform="rotate(90)" />
    <circle class="dot" r="4" />
  </svg>
  <p class="polar"><input type="number" value="0" class='magnitude' />@<input type="number" value="0" class='angle'/>°</p>
</div>
<script type="text/javascript"><![CDATA[
  var svg   = document.getElementsByTagName('svg')[0];
  var svgNS = svg.getAttribute('xmlns');
  var pt    = svg.createSVGPoint();

  function mxy(evt){
    pt.x = evt.clientX;
    pt.y = evt.clientY;
    return pt.matrixTransform(svg.getScreenCTM().inverse());
  }

  var dot  = document.querySelector('.complex-plane-picker .dot');
  var real = document.querySelector('.real');
  var imag = document.querySelector('.imaginary');
  var size = document.querySelector('.magnitude');
  var angl = document.querySelector('.angle');

  var labels = svg.querySelectorAll('.complex-plane-picker #labels text');
  var scale, maxValue;
  var updateScale = function(newScale){
    scale = newScale;
    maxValue = 50*scale;
    var tickSize=1e-6;
    var e=-5;
    var f=-1;
    var fs = [1,2,5]
    while (tickSize/scale < 10){
      if (++f%fs.length==0) ++e;
      tickSize = fs[f%fs.length]*Math.pow(10,e);
    }
    for (var i=labels.length;i;--i){
      labels[i-1].firstChild.nodeValue = (tickSize*i).toString().replace(/(\.0*[^0]+)0{3,}.*/,'$1');
      labels[i-1].setAttribute('y', -tickSize*i/scale);
    }
    // updateRectangularFromDot();
    // updatePolarFromDot();
  };

  var rescaleAsNeeded = function(x,y,jump){
    var scaleFactor = 1.03;
    if (jump && (x>maxValue || y>maxValue || (x<maxValue*0.1 && y<maxValue*0.1))){
      updateScale(Math.max(x,y)*2/50);
    } else if (x>maxValue*0.8 || y>maxValue*0.8) updateScale(scale*scaleFactor);
    else if (x<maxValue*0.1 && y<maxValue*0.1) updateScale(scale/scaleFactor);
  };  

  var updateFromRectangular = function(){
    var x = real.value*1;
    var y = imag.value*1;
    rescaleAsNeeded(x,y,true);
    dot.cx.baseVal.value =  x/scale;
    dot.cy.baseVal.value = -y/scale;
    updatePolarFromDot();
  };
  real.addEventListener('input',updateFromRectangular,false);
  imag.addEventListener('input',updateFromRectangular,false);

  var updateFromPolar = function(){
    var hyp = size.value*1;
    var rad = angl.value*Math.PI/180;
    var x   = Math.cos(rad)*hyp;
    var y   = Math.sin(rad)*hyp;
    rescaleAsNeeded(x,y,true);
    dot.cx.baseVal.value =  x/scale;
    dot.cy.baseVal.value = -y/scale;
    updateRectangularFromDot();
  };
  size.addEventListener('input',updateFromPolar,false);
  angl.addEventListener('input',updateFromPolar,false);

  var updateRectangularFromDot = function(){
    real.value = ( dot.cx.baseVal.value*scale).toFixed(2);
    imag.value = (-dot.cy.baseVal.value*scale).toFixed(2);
  };
  var updatePolarFromDot = function(){
    var x =  dot.cx.baseVal.value*scale;
    var y = -dot.cy.baseVal.value*scale;
    size.value = Math.sqrt(x*x+y*y).toFixed(2);
    angl.value = (Math.atan2(y,x)*180/Math.PI).toFixed(1);
  }
  var dragging = false;
  dot.addEventListener('mousedown',function(evt){
    var offset = mxy(evt);
    dragging = true;
    offset.x = dot.cx.baseVal.value - offset.x;
    offset.y = dot.cy.baseVal.value - offset.y;
    var scaleTimer;
    var move = function(evt){
      clearTimeout(scaleTimer);
      var now = mxy(evt);
      var x = offset.x + now.x;
      var y = -(offset.y + now.y);
      dot.cx.baseVal.value = x;
      dot.cy.baseVal.value = -y;
      x = Math.abs(x)*scale, y=Math.abs(y)*scale;
      var oldScale = scale;
      rescaleAsNeeded(x,y);
      updatePolarFromDot();
      updateRectangularFromDot();
      if (oldScale != scale) scaleTimer = setTimeout(function(){move(evt)},1000/30);
    };
    document.documentElement.style.userSelect = 
    document.documentElement.style.MozUserSelect = 
    document.documentElement.style.webkitUserSelect = 'none';
    svg.addEventListener('mousemove',move,false);
    document.documentElement.addEventListener('mouseup',function(){
      dragging = false;
      clearTimeout(scaleTimer);
      svg.removeEventListener('mousemove',move,false);
      document.documentElement.style.userSelect = 
      document.documentElement.style.MozUserSelect = 
      document.documentElement.style.webkitUserSelect = '';
    },false);
  },false);

  dot.addEventListener('dblclick',function(){
    dot.cx.baseVal.value = dot.cy.baseVal.value = 0;
    updateScale(1.0);
    updatePolarFromDot();
    updateRectangularFromDot();
  },false);

  updateScale(1.0);

]]></script>
</body></html>
于 2012-06-20T22:19:59.753 回答