رسم الأسهم على صفحة 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>
...

أي كل فترة لديه معرف ويشير إلى الصفر أو أكثر يمتد عبر معرفاتهم.

أرغب في تصور هذه المراجع كأحد الأسهم.

سؤالين:

  • كيف يمكنني تعيين معرف لمدة تمتد إلى إحداثيات الشاشة لتقديم الفترة؟
  • كيف يمكنني رسم الأسهم الذهاب من التقديم إلى آخر؟

يجب أن يعمل الحل في فايرفوكس، والعمل في متصفحات أخرى هو زائد ولكن ليس ضروريا حقا. الحل يمكن استخدام jquery، أو بعض مكتبة جافا سكريبت خفيفة الوزن الأخرى.

هل كانت مفيدة؟

المحلول

لديك خياران: SVG. أو اللوحة القماشية.

من مظهره، لا تحتاج إلى هذه الأسهم للحصول على أي شكل رياضي معين، تحتاج فقط إلى الذهاب بين العناصر.

يحاول الأسلاك. وبعد الق نظرة على هذا الأسلاك التجريبية (التي تم إهمالها). يستخدم أ canvas علامة لكل سلك فردي بين الحوار العائم divS، ثم أحجام ومواقف كل canvas عنصر لإعطاء مظهر خط اتصال في المكان الصحيح فقط. قد تضطر إلى تنفيذ رأس جوهر دوار إضافي، إلا إذا كنت لا تمانع في الأسهم الواردة في كل عنصر في نفس الزاوية.

يحرر: تم إهمال العرض التوضيحي.

يحرر: تجاهل هذه الإجابة، تضمين التغريدة دققت المسمار فيه

نصائح أخرى

تم التقاط هذا اهتمامي لفترة كافية لفترة كافية لإنتاج القليل من الاختبار. الرمز أدناه، ويمكنك أراها في العمل

screenshot

يسرد جميع المدعم على الصفحة (قد ترغب في تقييد ذلك فقط مع معرفات بدءا من T إذا كان ذلك مناسب)، ويستخدم سمة "المعرفات" لإنشاء قائمة الروابط. باستخدام عنصر قماش خلف تمتد، فإنه يرسم أسهم القوس بالتناوب أعلى وتحت يمتد لكل مصدر مصدر.

<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> 

وتحتاج فقط إلى مكالمة في مكان ما إلى دالة السحب ()

<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: ثابت، شكراvalo

آمل أن تكون مفيدة كما كانت ممتعة.

مكتبة رائعة للسهام المشتركة يعتمد ذلك على رافائيل كما هو موضح أعلاه. مع المشتركة يمكنك بسهولة رسم الأسهم مع المنحنيات أو القمم دون أي أشياء معقدة ؛-)

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

هذا يحدد سهم "J34" الذي يربط عن عناصر JS S3 مع S4. كل شيء آخر يمكن قراءته في توثيق المشتركة.

بامكانك ان تحاول هذه المكتبة - إنها أشياء ذكية للغاية، ونأمل أن يساعدها.

تحرير: لأن هذا الرابط ميت، وهنا رابط آخر من أرشيف.ورغ.

أحاول أن أذهب مع تقنيات الويب المفتوحة حيثما كان ذلك ممكنا ولكن الحقيقة هي أن HTML & JavaScript (أو JQuercript) ليست أدوات لهذه الوظيفة المعينة (حزينة ولكنها حقيقية)، خاصة كما تخطط الرسوم البيانية التي ترتفع فيها في التعقيد.

من ناحية أخرى، فلاش صنع لهذا. سيكون هناك حاجة إلى رمز ActionScript أقل بكثير لتحليل جهاز XML، تخطيط النص الخاص بك (مع التحكم في الخطوط والموسيقى / Super / Supplaccripts) وتقديم المنحنيات (انظر flash.display.graphics Class. طرق مثل curveTo). بشكل عام، ستبحث في أقل رمز، وصيانة أفضل، ومخالفات أقل، والتوافق على نطاق أوسع ومكتبات رسم أكثر استقرارا.

حظا سعيدا مع المشروع.

إذا كنت لا تحتاج إلى أسهم منحنية، فيمكنك استخدام Divs في وضع مطلقا أعلاه أو أسفل القائمة. يمكنك بعد ذلك استخدام CSS إلى نمط تلك Divs بالإضافة إلى بضعة صور تشكل رأس الأسهم. فيما يلي مثال على ذلك باستخدام الأيقونة المضطربة من مشروع 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>

الآن يمكننا البدء في تجميع السهم divs. على سبيل المثال، إلى نمط السهم من "يتطلب" على "المروج" في مثالك أعلاه، يمكنك القيام بالحدود اليسرى والسفلي واليمين على 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 فارغة. إنه نوع من أنيق.

كما ذكر آخرون، فإن جافا سكريبت و HTML ليست أدوات جيدة لهذا النوع من الأشياء.

كتب جون ريسجن تنفيذ المعالجة .org في جافا سكريبت. وبعد يستخدم عنصر قماش، لذلك سيعمل في الإصدارات الحديثة من فايرفوكس، لكنه لن يعمل في جميع المتصفحات. إذا كنت تهتم فقط بفايرفوكس، فمن المحتمل أن يكون هذا هو الطريق للذهاب.

قد تكون قادرا على استخدام SVG، ولكن مرة أخرى، هذا غير مدعوم في جميع المتصفحات.

كنت بحاجة إلى حل مماثل، وكنت أبحث في مكتبة raphaeljs جافا سكريبت. وبعد على سبيل المثال، يمكنك رسم سهم مستقيم من (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];
}

ليس لدي كيفية رسم سهم منحني، لكنني متأكد من أنه من الممكن.

هل يمكن أن تحصل على arrow المنحني ينتهي باستخدام حفنة من position:absolute divs مع background-image تعيين لتصريف الصور الشفافة ... مجموعة للبداية (أعلى وأسفل) ... bacground:repeat DIV من أجل منتصف التداول، وزوج آخر للنهايات (أعلى وأسفل).

يمكنك استخدام هذه المكتبة: تعلن فقط خطوط SVG الخاصة بك مع معرفات المصدر والهدف المستهدف. ويستخدم ذلك minationobserver. لمراقبة التغييرات في العناصر المتصلة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top