드로잉에서 화살표 HTML 페이지를 시각화하는 시맨틱 링크 사이에 걸쳐 있는 텍스트

StackOverflow https://stackoverflow.com/questions/554167

  •  23-08-2019
  •  | 
  •  

문제

나는 HTML 페이지 어떤 텍스트에 걸쳐 표가 다음과 같다:

...
<span id="T2" class="Protein">p50</span>
...
<span id="T3" class="Protein">p65</span>
...
<span id="T34" ids="T2 T3" class="Positive_regulation">recruitment</span>
...

I.e.각 범위의 ID 및을 참조하거나 하나 이상에 걸쳐 통해 자신의 Id 입니다.

고 싶을 시각화하는 이러한 참조로 화살표입니다.

두 가지 질문:

  • 할 수 있는 방법 지도 ID 의 범위기의 화면 좌표를 렌더링 span?
  • 어떻게 그리는 화살표로 하나에서 렌더링을까?

이 솔루션을 작동해야에서 Firefox 에서 일하고,다른 브라우저 플러스 하지만 정말 필요하지 않습니다.솔루션 사용할 수 있습 jQuery,또는 기타 라 자바 스크립트 라이브러리입니다.

도움이 되었습니까?

해결책

몇 가지 옵션이 있습니다. SVG 또는 캔버스.

그것의 외관에서 당신은 특정 수학적 형태를 갖기 위해 이러한 화살표가 필요하지 않으므로 요소 사이를 가야합니다.

노력하다 와이어. 이것을 살펴보십시오 와이어 데모 (더 이상 사용되지 않았습니다). a canvas 부동 대화 상자 사이의 각 개별 와이어에 대한 태그 divS, 크기 및 위치 각각 canvas 올바른 지점에서 연결 라인의 모양을 제공하는 요소. 동일한 각도로 화살표가 각 요소에 들어오는 화살표를 신경 쓰지 않는 한 추가 회전 화살촉을 구현해야 할 수도 있습니다.

편집하다: 데모는 더 이상 사용되지 않았습니다.

편집하다:이 답을 무시하고 @phil h 그것을 못 박았습니다

다른 팁

이것은 약간의 테스트를 만들기에 충분히 오랫동안 나의 관심을 사로 잡았습니다. 코드는 아래에 있으며 가능합니다 실제로보십시오

screenshot

페이지의 모든 스팬을 나열하고 (적합한 경우 T로 시작하는 ID를 가진 사람들에게만 제한 할 수 있음) 'IDS'속성을 사용하여 링크 목록을 작성합니다. 스팬 뒤에 캔버스 요소를 사용하면 각 소스 범위의 스팬 위와 아래에 아크 화살표가 번갈아갑니다.

<script type="application/x-javascript"> 

function generateNodeSet() {
  var spans = document.getElementsByTagName("span");
  var retarr = [];
  for(var i=0;i<spans.length; i++) { 
     retarr[retarr.length] = spans[i].id; 
  } 
  return retarr; 
} 

function generateLinks(nodeIds) { 
  var retarr = []; 
  for(var i=0; i<nodeIds.length; i++) { 
    var id = nodeIds[i];
    var span = document.getElementById(id); 
    var atts = span.attributes; 
    var ids_str = false; 
    if((atts.getNamedItem) && (atts.getNamedItem('ids'))) { 
      ids_str = atts.getNamedItem('ids').value; 
    } 
    if(ids_str) { 
      retarr[id] = ids_str.split(" ");
    }
  } 
  return retarr; 
} 

// degrees to radians, because most people think in degrees
function degToRad(angle_degrees) {
   return angle_degrees/180*Math.PI;
}
// draw a horizontal arc
//   ctx: canvas context;
//   inax: first x point
//   inbx: second x point
//   y: y value of start and end
//   alpha_degrees: (tangential) angle of start and end
//   upside: true for arc above y, false for arc below y.
function drawHorizArc(ctx, inax, inbx, y, alpha_degrees, upside)
{
  var alpha = degToRad(alpha_degrees);
  var startangle = (upside ? ((3.0/2.0)*Math.PI + alpha) : ((1.0/2.0)*Math.PI - alpha));
  var endangle = (upside ? ((3.0/2.0)*Math.PI - alpha) : ((1.0/2.0)*Math.PI + alpha));

  var ax=Math.min(inax,inbx);
  var bx=Math.max(inax,inbx);

  // tan(alpha) = o/a = ((bx-ax)/2) / o
  // o = ((bx-ax)/2/tan(alpha))
  // centre of circle is (bx+ax)/2, y-o
  var circleyoffset = ((bx-ax)/2)/Math.tan(alpha);
  var circlex = (ax+bx)/2.0;
  var circley = y + (upside ? 1 : -1) * circleyoffset;
  var radius = Math.sqrt(Math.pow(circlex-ax,2) + Math.pow(circley-y,2));

  ctx.beginPath();
  if(upside) {
      ctx.moveTo(bx,y);
    ctx.arc(circlex,circley,radius,startangle,endangle,1);
  } else {
    ctx.moveTo(bx,y);
    ctx.arc(circlex,circley,radius,startangle,endangle,0);
  }
  ctx.stroke();
}


// draw the head of an arrow (not the main line)
//  ctx: canvas context
//  x,y: coords of arrow point
//  angle_from_north_clockwise: angle of the line of the arrow from horizontal
//  upside: true=above the horizontal, false=below
//  barb_angle: angle between barb and line of the arrow
//  filled: fill the triangle? (true or false)
function drawArrowHead(ctx, x, y, angle_from_horizontal_degrees, upside, //mandatory
                       barb_length, barb_angle_degrees, filled) {        //optional
   (barb_length==undefined) && (barb_length=13);
   (barb_angle_degrees==undefined) && (barb_angle_degrees = 20);
   (filled==undefined) && (filled=true);
   var alpha_degrees = (upside ? -1 : 1) * angle_from_horizontal_degrees; 

   //first point is end of one barb
   var plus = degToRad(alpha_degrees - barb_angle_degrees);
   a = x + (barb_length * Math.cos(plus));
   b = y + (barb_length * Math.sin(plus));

   //final point is end of the second barb
   var minus = degToRad(alpha_degrees + barb_angle_degrees);
   c = x + (barb_length * Math.cos(minus));
   d = y + (barb_length * Math.sin(minus));

   ctx.beginPath();
   ctx.moveTo(a,b);
   ctx.lineTo(x,y);
   ctx.lineTo(c,d);
   if(filled) {
    ctx.fill();
   } else {
    ctx.stroke();
   }
   return true;
}

// draw a horizontal arcing arrow
//  ctx: canvas context
//  inax: start x value
//  inbx: end x value
//  y: y value
//  alpha_degrees: angle of ends to horizontal (30=shallow, >90=silly)
function drawHorizArcArrow(ctx, inax, inbx, y,                 //mandatory
                           alpha_degrees, upside, barb_length) { //optional
   (alpha_degrees==undefined) && (alpha_degrees=45);
   (upside==undefined) && (upside=true);
   drawHorizArc(ctx, inax, inbx, y, alpha_degrees, upside);
   if(inax>inbx) { 
    drawArrowHead(ctx, inbx, y, alpha_degrees*0.9, upside, barb_length); 
   } else { 
    drawArrowHead(ctx, inbx, y, (180-alpha_degrees*0.9), upside, barb_length); 
   }
   return true;
}


function drawArrow(ctx,fromelem,toelem,    //mandatory
                     above, angle) {        //optional
  (above==undefined) && (above = true);
  (angle==undefined) && (angle = 45); //degrees 
  midfrom = fromelem.offsetLeft + (fromelem.offsetWidth / 2) - left - tofromseparation/2; 
  midto   =   toelem.offsetLeft + (  toelem.offsetWidth / 2) - left + tofromseparation/2;
  //var y = above ? (fromelem.offsetTop - top) : (fromelem.offsetTop + fromelem.offsetHeight - top);
  var y = fromelem.offsetTop + (above ? 0 : fromelem.offsetHeight) - canvasTop;
  drawHorizArcArrow(ctx, midfrom, midto, y, angle, above);
}

    var canvasTop = 0;
function draw() { 
  var canvasdiv = document.getElementById("canvas");
  var spanboxdiv = document.getElementById("spanbox");
  var ctx = canvasdiv.getContext("2d");

  nodeset = generateNodeSet(); 
  linkset = generateLinks(nodeset);
  tofromseparation = 20;

  left = canvasdiv.offsetLeft - spanboxdiv.offsetLeft;
  canvasTop = canvasdiv.offsetTop - spanboxdiv.offsetTop; 
  for(var key in linkset) {  
    for (var i=0; i<linkset[key].length; i++) {  
      fromid = key; 
      toid = linkset[key][i]; 
      var above = (i%2==1);
      drawArrow(ctx,document.getElementById(fromid),document.getElementById(toid),above);
    } 
  } 
} 

</script> 

Draw () 함수의 어딘가에 전화가 필요합니다.

<body onload="draw();"> 

그런 다음 스팬 세트 뒤에 캔버스가 있습니다.

<canvas style='border:1px solid red' id="canvas" width="800" height="7em"></canvas><br /> 
<div id="spanbox" style='float:left; position:absolute; top:75px; left:50px'>
<span id="T2">p50</span>
...
<span id="T3">p65</span> 
...
<span id="T34" ids="T2 T3">recruitment</span>
</div> 

내가 볼 수있는 한 향후 수정 :

  • 더 긴 화살표의 상단을 평평하게합니다
  • 비 유산 화살표를 그릴 수 있도록 리팩토링 : 각각에 새 캔버스를 추가 하시겠습니까?
  • 더 나은 루틴을 사용하여 캔버스 및 스팬 요소의 총 오프셋을 얻으십시오.

2011 년 12 월 편집 : 고정, 감사합니다 @palo

그것이 재미 있었던 것만 큼 유용하기를 바랍니다.

화살표를위한 훌륭한 도서관입니다 공동 js 그것은 위와 같이 라파엘을 기반으로합니다. 조인트를 사용하면 복잡한 물건없이 곡선이나 정점으로 화살표를 쉽게 그릴 수 있습니다 ;-)

var j34 = s3.joint(s4, uml.arrow).setVertices(["170 130", "250 120"]);

이것은 두 개의 JS 항목 S3을 S4와 연결하는 화살표 'J34'를 정의합니다. 다른 모든 것은 conterjs의 문서에서 읽을 수 있습니다.

당신은 시도 할 수 있습니다 이 도서관 - 매우 영리한 것입니다. 도움이되기를 바랍니다.

편집 :이 링크가 죽었으므로 여기에 또 다른 링크가 있습니다. archive.org.

나는 가능한 한 열린 웹 기술을 사용하려고 노력하지만 진실은 HTML & JavaScript (또는 jQuery) 가이 특정 작업 (슬픈 일이지만 사실)의 도구가 아니라는 것입니다.

반면에, 플래시 이것을 위해 만들어졌습니다. XML, 텍스트를 레이아웃 (글꼴 및 슈퍼/구독에 대한 더 많은 제어 기능)을 구문 분석하고 곡선을 렌더링하는 데 필요한 ActionScript 3.0 코드가 훨씬 적습니다 (참조하십시오. Flash.display.graphics 클래스 와 같은 방법 curveTo). 전반적으로 코드가 적고 유지 관리가 더 적고 해킹이 적고, 더 넓은 호환성 및 더 안정적인 드로잉 라이브러리를 살펴볼 것입니다.

프로젝트에 행운을 빕니다.

이 필요하지 않다면 곡면 화살표 사용할 수 있습니다 절대 위치 div 위 또는 아래의 목록입니다.다음 사용할 수 있습 css 스타일을 그 div 플러스 부부의 이미지를 만드는 화살 머리입니다.아래 예에서 아이콘을 사용하여 설정에서 jQuery UI 프로젝트(미안해 긴 URL).

여기에 CSS 일 시작하기:

<style>
 .below{
     border-bottom:1px solid #000;
     border-left:1px solid #000;
     border-right:1px solid #000;
 }
 .below span{
    background-position:0px -16px;
    top:-8px;
 }
 .above{
     border-top:1px solid #000;
     border-left:1px solid #000;
     border-right:1px solid #000;
 }
 .above span{
    background-position:-64px -16px;
    bottom:-8px;
 }

 .arrow{
    position:absolute;
    display:block;
    background-image:url(http://jquery-ui.googlecode.com/svn/trunk/themes/base/images/ui-icons_454545_256x240.png);
    width:16px;
    height:16px;
    margin:0;
    padding:0;
 }

.left{left:-8px;}

.right{right:-9px;}

</style>

지금 우리가 시작할 수 있습니다 모이는 화살표 div.예를 들면,스타일 화살표에서"필요합"을"발"에서 위의 예에서,당신이 할 수 있는 왼쪽,하단 오른쪽에 div 으로 그리고 상승에 직면 화살표 그래픽 왼쪽 상단에서의 div.

<div class='below' style="position:absolute;top:30px;left:30px;width:100px;height:16px">
   <span class='arrow left'></span>
</div>

인라인 스타일 것 적용해야에 의해 스크립트를 알아낸 후의 위치를 것을 필요가를 연결합니다.말하자는 목록은 다음과 같습니다:

<span id="promoter">Promoter</span><span>Something Else</span><span id="requires">Requires</span>

다음과 같은 스크립트가 위치하 화살표:

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script> 
<script>
$(function(){
 var promoterPos=$("#promoter").offset();
 var requiresPos=$("#requires").offset();
 $("<div class='below'><span class='arrow left'></span></div>")
 .css({position:"absolute",left:promoterPos.left,right:promoterPos.top+$("#promoter").height()})
 .width(requiresPos.left-promoterPos.left)
 .height(16)
 .appendTo("body");
});
</script>

가 붙여 위의 예제로는 빈 html 페이지입니다.그것의 종류의 깔끔합니다.

다른 사람들이 언급했듯이 JavaScript와 HTML은 이런 종류의 일에 좋은 도구가 아닙니다.

John Resig는 썼습니다 JavaScript에서 Processing.org 구현. 캔버스 요소를 사용하므로 최신 버전의 Firefox에서 작동하지만 모든 브라우저에서 작동하지 않습니다. Firefox에만 관심이 있다면 이것은 아마도 갈 길일 것입니다.

SVG를 사용할 수는 있지만 모든 브라우저에서 지원되는 것은 아닙니다.

비슷한 해결책이 필요했고 조사했습니다. Raphaeljs JavaScript 라이브러리. 예를 들어 직선 화살표를 그릴 수 있습니다 (x1,y1) 에게 (x2,y2) 와 함께:

Raphael.fn.arrow = function (x1, y1, x2, y2, size) {
  var angle = Math.atan2(x1-x2,y2-y1);
  angle = (angle / (2 * Math.PI)) * 360;
  var arrowPath = this.path(“M” + x2 + ” ” + y2 + ” L” + (x2 - size) + ” ” + (y2 - size) + ” L” + (x2 - size) + ” ” + (y2 + size) + ” L” + x2 + ” ” + y2 ).attr(“fill”,”black”).rotate((90+angle),x2,y2);
  var linePath = this.path(“M” + x1 + ” ” + y1 + ” L” + x2 + ” ” + y2);
  return [linePath,arrowPath];
}

곡선 화살표를 그리는 방법을 알지 못했지만 가능할 것이라고 확신합니다.

소수를 사용하여 구부러진 화살표 끝을 얻을 수 있습니다. position:absolute div background-image 투명한 GIF로 설정 ... 시작을위한 세트 (상단 및 하단) ... A bacground:repeat 확장 가능한 중간에 대한 Div 및 끝과 아래의 다른 쌍 (상단 및 하단).

당신이 사용할 수있는 이 도서관: 소스 및 대상 요소의 ID와 SVG 라인에 주석을 달 수 있습니다. 사용합니다 돌연변이 관상 서버 연결된 요소의 변화를 관찰합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top