Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/82.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 通过可拖动的SVG形状设置HTML输入值?(或画布)_Javascript_Html_Svg - Fatal编程技术网

Javascript 通过可拖动的SVG形状设置HTML输入值?(或画布)

Javascript 通过可拖动的SVG形状设置HTML输入值?(或画布),javascript,html,svg,Javascript,Html,Svg,我正在尝试组装一个GUI来设置一些定价。 有三个类别以图形方式表示,两个滑块用于设置建议的买入/卖出价格 作为练习,我拼凑了一些原型并将它们放在一起。 请快速看一下,它将比我的话更有效地解释它:) (请原谅我的JS…还没有重构) 因为我们的目标是让滑块在HTML输入中设置浮点,所以我倾向于SVG 我的第一个请求只是对我选择的SVG解决方案进行同行评审。。。只是想确保我不会遇到一些固有的和痛苦的障碍。我也对其他解决方案持开放态度 第二个问题。有没有人有好的链接/示例可以帮助我理解如何根据形状的位置

我正在尝试组装一个GUI来设置一些定价。
有三个类别以图形方式表示,两个滑块用于设置建议的买入/卖出价格

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

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

  • 我的第一个请求只是对我选择的SVG解决方案进行同行评审。。。只是想确保我不会遇到一些固有的和痛苦的障碍。我也对其他解决方案持开放态度
  • 第二个问题。有没有人有好的链接/示例可以帮助我理解如何根据形状的位置设置输入值 (我希望该位置代表定义的$$范围的百分比,因此我们可以推断特定的$$值)


    非常感谢所有的帮助。

    这里是我制作的一个演示,它使用SVG设置四个输入,反之亦然:

    前两个输入是X和Y(实部和复部);底部两个是极坐标(幅值和角度)

    那里可能有比您需要的更多的代码(当您接近边缘/中间时自动缩放,绘制更新的轴标记),这可能会使演示更混乱,而不是更有用

    但是,一般来说,您需要:

    • 在输入的
      键控
      更改
      输入
      事件上有一个事件侦听器,并相应地更新SVG以匹配
    • 将拖动添加到SVG元素中,并在拖动过程中计算适当的值,并相应地为输入设置
      .value
    作为提示,在拖动过程中,不要试图检测可拖动元素本身上的
    mousemove
    。如果鼠标移到这个范围之外,您将停止获取拖动事件,它将无法跟上。相反,我通常使用以下逻辑:

    • mousedown
      上:
    • 记录当前光标位置
    • 在文档的根目录上注册
      mousemove
      handler
    • 在文档的根目录上注册
      mouseup
      handler
    • mousemove
      上:
    • 检测当前光标位置和拖动开始位置之间的屏幕空间增量,并使用此增量更新其转换
    • mouseup上
    • 注销
      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>
    
    
    SVG复平面输入
    html,正文{背景:#eee;边距:0}
    p{边距:0.5em;文本对齐:中心}
    .complex plane picker svg{width:200px;height:200px;display:block;margin:1em auto;stroke linejoin:round;stroke linecap:round;指针事件:all;}
    .complex plane picker rect.bg{fill:#fff;}
    .complex plane picker.axes*{stroke:#ccc;fill:none}
    .complex plane picker.dot{fill:#090;填充不透明度:0.4;笔划:#000;笔划不透明度:0.6;光标:移动;}
    .complex平面选择器输入{width:6em;}
    .complex plane picker.标签{笔划:无;字体大小:6px;字体系列:'Verdana';文本定位:中间;对齐基线:中间;}
    .complex plane picker.scaler{指针事件:all;}
    拖动点以设置复数值。
    TODO:按住shift键仅影响幅值。按住alt键仅影响角度。按住这两个键可捕捉到最接近的纯实值或纯虚值

    +i

    0 0 0 0

    maxValue | | y>maxValue | |(xmaxValue*0.8)updateScale(scale*scaleFactor);
    否则,如果(xFyi,你网站上的SHIFT和ALT修饰符对我不起作用(Chrome&FF)。@mOrloff这就是为什么它前面写着“TODO”;很明显,我从那个项目中分心了,从来没有完成过这些功能;)如果你把它变成一个教程,甚至只是在你的JavaScript中加入大量非常描述性的注释,那就太酷了。。。JS对我来说仍然有点不自然,我正试图把它拆开,理解它,并保持它的完整性,但我相当挣扎:)@mOrloff我会看看我是否能找到时间来做这件事。嗯@Phrogz,我的修补已经让我走得很远了。我已经把它精简到。。我的下一步是让它玩两个滑块好。。如果我可以就问题与您联系,请在粘贴底部的电子邮件中ping我。。无论如何,非常感谢:)我非常同意您选择SVG而不是画布;当你需要每个对象事件处理和简单更新时,使用像canvas这样的即时模式绘图系统只需要额外的工作。哦,当然,你知道,对吧?@Phrogz,谢谢。。。我原本希望使用范围输入,但FF的不支持扼杀了这个梦想:)