Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Connect two div by line with jquery function

I have two groups of quiz.
The first group is correct but the second group is not showing the line between two points.

The users click the point on the left and click the point on the right, then JavaScript creates a "canvas" line from the first element to the second element. (I apologise for my english, it's my second language)

enter image description here

(function($) {
  $.fn.connect = function(param) {
    var _canvas;
    var _ctx;
    var _lines = new Array(); //This array will store all lines (option)
    var _me = this;
    var _parent = param || document;
    var _lengthLines = $(_parent + ' .group1 .node').length;
    var _selectFirst = null;
    //Initialize Canvas object

    _canvas = $('<canvas/>')
      .attr('width', $(_me).width())
      .attr('height', $(_me).height())
      .css('position', 'absolute');
    $(_parent).prepend(_canvas);
    //$(_canvas).insertBefore(_parent);
    this.drawLine = function(option) {
      //It will push line to array.
      _lines.push(option);
      this.connect(option);

    };

    this.drawAllLine = function(option) {

      /*Mandatory Fields------------------
      left_selector = '.class',
      data_attribute = 'data-right',
      */

      if (option.left_selector != '' && typeof option.left_selector !== 'undefined' && $(option.left_selector).length > 0) {
        $(option.left_selector).each(function(index) {
          var option2 = new Object();
          $.extend(option2, option);
          option2.left_node = $(this).attr('id');
          option2.right_node = $(this).data(option.data_attribute);
          if (option2.right_node != '' && typeof option2.right_node !== 'undefined') {
            _me.drawLine(option2);

          }
        });
      }
    };

    //This Function is used to connect two different div with a dotted line.
    this.connect = function(option) {

      _ctx = _canvas[0].getContext('2d');
      //
      _ctx.beginPath();
      try {
        var _color;
        var _dash;
        var _left = new Object(); //This will store _left elements offset  
        var _right = new Object(); //This will store _right elements offset	
        var _error = (option.error == 'show') || false;
        /*
        option = {
        	left_node - Left Element by ID - Mandatory
        	right_node - Right Element ID - Mandatory
        	status - accepted, rejected, modified, (none) - Optional
        	style - (dashed), solid, dotted - Optional	
        	horizantal_gap - (0), Horizantal Gap from original point
        	error - show, (hide) - To show error or not
        	width - (2) - Width of the line
        }
        */

        if (option.left_node != '' && typeof option.left_node !== 'undefined' && option.right_node != '' && typeof option.right_node !== 'undefined' && $(option.left_node).length > 0 && $(option.right_node).length > 0) {

          //To decide colour of the line
          switch (option.status) {
            case 'accepted':
              _color = '#0969a2';
              break;

            case 'rejected':
              _color = '#e7005d';
              break;

            case 'modified':
              _color = '#bfb230';
              break;

            case 'none':
              _color = 'grey';
              break;

            default:
              _color = 'grey';
              break;
          }

          //To decide style of the line. dotted or solid
          switch (option.style) {
            case 'dashed':
              _dash = [4, 2];
              break;

            case 'solid':
              _dash = [0, 0];
              break;

            case 'dotted':
              _dash = [4, 2];
              break;

            default:
              _dash = [4, 2];
              break;
          }
          /*
          	console.log($(option.left_node));
          	$(option.left_node)
          	$(option.right_node).data('connect',true);
          */
          //If left_node is actually right side, following code will switch elements.
          $(option.right_node).each(function(index, value) {
            _left_node = $(option.left_node);
            _right_node = $(value);

            _left_node.attr('data-connect', true);
            _right_node.attr('data-connect', true);

            if (_left_node.offset().left >= _right_node.offset().left) {
              _tmp = _left_node
              _left_node = _right_node
              _right_node = _tmp;
            }

            //Get Left point and Right Point
            _left.x = _left_node.offset().left + _left_node.outerWidth();
            _left.y = _left_node.offset().top + (_left_node.outerHeight() / 2);
            _right.x = _right_node.offset().left;
            _right.y = _right_node.offset().top + (_right_node.outerHeight() / 2);

            //Create a group
            //var g = _canvas.group({strokeWidth: 2, strokeDashArray:_dash}); 	

            //Draw Line
            var _gap = option.horizantal_gap || 0;

            _ctx.moveTo(_left.x, _left.y);
            if (_gap != 0) {
              _ctx.lineTo(_left.x + _gap, _left.y);
              _ctx.lineTo(_right.x - _gap, _right.y);
            }
            _ctx.lineTo(_right.x, _right.y);

            if (!_ctx.setLineDash) {
              _ctx.setLineDash = function() {}
            } else {
              _ctx.setLineDash(_dash);
            }
            _ctx.lineWidth = option.width || 2;
            _ctx.strokeStyle = _color;
            _ctx.stroke();
          });
          
          //option.resize = option.resize || false;
        } else {
          if (_error) alert('Mandatory Fields are missing or incorrect');
        }
      } catch (err) {
        if (_error) alert('Mandatory Fields are missing or incorrect');
      }
      //console.log(_canvas);
    };

    //It will redraw all line when screen resizes
    $(window).resize(function() {
      console.log(_me);
      _me.redrawLines();
    });

    $(_parent + ' .group1 .node span').click(function() {
      //console.log($(this).attr('data-connect'));
      //[data-use="false"]
      _this = this;
      if ($(_this).attr('data-connect') != 'true' && $(_this).attr('data-use') == 'false') {
        $(_parent + ' .group1 .node span').attr('data-use', 'false');
        $(_this).attr('data-use', 'true');
        _selectFirst = _this;
      } else if ($(_this).attr('data-connect') == 'true') {
        //console.log($(this).attr('data-id'));
        //console.log(entry);
        _lines.forEach(function(entry, index) {
          if ($(_this).attr('data-id') == entry.id_left) {
            $(entry.left_node).attr('data-use', 'false').attr('data-connect', 'false')
            $(entry.right_node).attr('data-use', 'false').attr('data-connect', 'false')
            _lines.splice(index, 1)
          }
        });
        _me.redrawLines();
      }
    });

    $(_parent + ' .group2 .node span[data-use="false"]').click(function() {
      if ($(_parent + ' .group1 .node span[data-use="true"]').length == 1 && _selectFirst != null) {
        if ($(this).attr('data-connect') != 'true') {
          _me.drawLine({
            id_left: $(_selectFirst).attr('data-id'),
            id_right: $(this).attr('data-id'),
            left_node: _selectFirst,
            right_node: this,
            horizantal_gap: 10,
            error: 'show',
            width: 1,
            status: 'accepted'
          });
          $(_selectFirst).attr('data-use', 'false');
          $(_selectFirst).attr('data-connect', 'true');
          $(this).attr('data-use', 'false');
          $(this).attr('data-connect', 'true');
        }
      }
    });

    this.redrawLines = function() {
      _ctx.clearRect(0, 0, $(_me).width(), $(_me).height());
      _lines.forEach(function(entry) {
        entry.resize = true;
        _me.connect(entry);
      });
    };
    return this;
  };
}(jQuery));
.clearfix {
  clear: both;
}

body {
  padding: 0px;
  margin: 0px;
}

.nodes {
  width: 500px
}

.node {
  width: 100px;
  background: #ddd;
  color: #fff;
  margin-bottom: 10px;
}

.group1 span {
  background: #666;
  border-radius: 50%;
  width: 10px;
  height: 10px;
  margin-top: 5px;
}

.group2 span {
  border: 1px solid #666;
  border-radius: 50%;
  width: 10px;
  height: 10px;
  margin-top: 5px;
}

.node span:hover {
  background: #ff0000;
  cursor: pointer;
}

.group1 {
  float: left;
}

.group2 {
  float: right;
}

.group2 .node span {
  float: left;
  position: relative;
  left: -15px;
}

.group1 .node span {
  float: right;
  position: relative;
  right: -15px;
}

.node span[data-connect=true] {
  background: #ff00ff !important;
}

.node span[data-use=true] {
  background: #ff0000 !important;
}
<div id="parentNodes_11">
  <div class="nodes">
    <div class="group1">
      <div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
      <div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
      <div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
    </div>
    <div class="group2">
      <div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
      <div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
      <div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
    </div>
    <div class="clearfix"></div>
  </div>
</div>
<br>
<div id="parentNodes_12">
  <div class="nodes">
    <div class="group1">
      <div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
      <div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
      <div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
    </div>
    <div class="group2">
      <div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
      <div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
      <div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
    </div>
    <div class="clearfix"></div>
  </div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script type="text/javascript">
  $(document).ready(function() {
    $('#parentNodes_11 .nodes').connect('#parentNodes_11');
    $('#parentNodes_12 .nodes').connect('#parentNodes_12');
  });
</script>
like image 701
HunTer AnDone Avatar asked May 31 '26 13:05

HunTer AnDone


1 Answers

This is due to the use of absolute coordinates for lines instead of relative ones, so your lines doesn't fit on the canvas.

You can just do the parent offset adjustment and it will work like this:

(function($) {
  $.fn.connect = function(param) {
    var _canvas;
    var _ctx;
    var _lines = new Array(); //This array will store all lines (option)
    var _me = this;
    var _parent = param || document;
    var _lengthLines = $(_parent + ' .group1 .node').length;
    var _selectFirst = null;
    //Initialize Canvas object

    _canvas = $('<canvas/>')
      .attr('width', $(_me).width())
      .attr('height', $(_me).height())
      .css('position', 'absolute');
    $(_parent).prepend(_canvas);
    //$(_canvas).insertBefore(_parent);
    this.drawLine = function(option) {
      //It will push line to array.
      _lines.push(option);
      this.connect(option);

    };

    this.drawAllLine = function(option) {

      /*Mandatory Fields------------------
      left_selector = '.class',
      data_attribute = 'data-right',
      */

      if (option.left_selector != '' && typeof option.left_selector !== 'undefined' && $(option.left_selector).length > 0) {
        $(option.left_selector).each(function(index) {
          var option2 = new Object();
          $.extend(option2, option);
          option2.left_node = $(this).attr('id');
          option2.right_node = $(this).data(option.data_attribute);
          if (option2.right_node != '' && typeof option2.right_node !== 'undefined') {
            _me.drawLine(option2);

          }
        });
      }
    };

    //This Function is used to connect two different div with a dotted line.
    this.connect = function(option) {

      _ctx = _canvas[0].getContext('2d');
      //
      _ctx.beginPath();
      try {
        var _color;
        var _dash;
        var _left = new Object(); //This will store _left elements offset  
        var _right = new Object(); //This will store _right elements offset 
        var _error = (option.error == 'show') || false;
        /*
        option = {
            left_node - Left Element by ID - Mandatory
            right_node - Right Element ID - Mandatory
            status - accepted, rejected, modified, (none) - Optional
            style - (dashed), solid, dotted - Optional  
            horizantal_gap - (0), Horizantal Gap from original point
            error - show, (hide) - To show error or not
            width - (2) - Width of the line
        }
        */

        if (option.left_node != '' && typeof option.left_node !== 'undefined' && option.right_node != '' && typeof option.right_node !== 'undefined' && $(option.left_node).length > 0 && $(option.right_node).length > 0) {

          //To decide colour of the line
          switch (option.status) {
            case 'accepted':
              _color = '#0969a2';
              break;

            case 'rejected':
              _color = '#e7005d';
              break;

            case 'modified':
              _color = '#bfb230';
              break;

            case 'none':
              _color = 'grey';
              break;

            default:
              _color = 'grey';
              break;
          }

          //To decide style of the line. dotted or solid
          switch (option.style) {
            case 'dashed':
              _dash = [4, 2];
              break;

            case 'solid':
              _dash = [0, 0];
              break;

            case 'dotted':
              _dash = [4, 2];
              break;

            default:
              _dash = [4, 2];
              break;
          }
          /*
            console.log($(option.left_node));
            $(option.left_node)
            $(option.right_node).data('connect',true);
          */
          //If left_node is actually right side, following code will switch elements.
          $(option.right_node).each(function(index, value) {
            _left_node = $(option.left_node);
            _right_node = $(value);

            _left_node.attr('data-connect', true);
            _right_node.attr('data-connect', true);

            if (_left_node.offset().left >= _right_node.offset().left) {
              _tmp = _left_node
              _left_node = _right_node
              _right_node = _tmp;
            }

            //Get Left point and Right Point
            _left.x = _left_node.offset().left + _left_node.outerWidth();
            _left.y = _left_node.offset().top + (_left_node.outerHeight() / 2) - _left_node.parents('.nodes').offset().top;
            _right.x = _right_node.offset().left;
            _right.y = _right_node.offset().top + (_right_node.outerHeight() / 2) - _right_node.parents('.nodes').offset().top; 

            //Create a group
            //var g = _canvas.group({strokeWidth: 2, strokeDashArray:_dash});   

            //Draw Line
            var _gap = option.horizantal_gap || 0;

            _ctx.moveTo(_left.x, _left.y);
            if (_gap != 0) {
              _ctx.lineTo(_left.x + _gap, _left.y);
              _ctx.lineTo(_right.x - _gap, _right.y);
            }
            _ctx.lineTo(_right.x, _right.y);

            if (!_ctx.setLineDash) {
              _ctx.setLineDash = function() {}
            } else {
              _ctx.setLineDash(_dash);
            }
            _ctx.lineWidth = option.width || 2;
            _ctx.strokeStyle = _color;
            _ctx.stroke();
          });
          
          //option.resize = option.resize || false;
        } else {
          if (_error) alert('Mandatory Fields are missing or incorrect');
        }
      } catch (err) {
        if (_error) alert('Mandatory Fields are missing or incorrect');
      }
      //console.log(_canvas);
    };

    //It will redraw all line when screen resizes
    $(window).resize(function() {
      console.log(_me);
      _me.redrawLines();
    });

    $(_parent + ' .group1 .node span').click(function() {
      //console.log($(this).attr('data-connect'));
      //[data-use="false"]
      _this = this;
      if ($(_this).attr('data-connect') != 'true' && $(_this).attr('data-use') == 'false') {
        $(_parent + ' .group1 .node span').attr('data-use', 'false');
        $(_this).attr('data-use', 'true');
        _selectFirst = _this;
      } else if ($(_this).attr('data-connect') == 'true') {
        //console.log($(this).attr('data-id'));
        //console.log(entry);
        _lines.forEach(function(entry, index) {
          if ($(_this).attr('data-id') == entry.id_left) {
            $(entry.left_node).attr('data-use', 'false').attr('data-connect', 'false')
            $(entry.right_node).attr('data-use', 'false').attr('data-connect', 'false')
            _lines.splice(index, 1)
          }
        });
        _me.redrawLines();
      }
    });

    $(_parent + ' .group2 .node span[data-use="false"]').click(function() {
      if ($(_parent + ' .group1 .node span[data-use="true"]').length == 1 && _selectFirst != null) {
        if ($(this).attr('data-connect') != 'true') {
          _me.drawLine({
            id_left: $(_selectFirst).attr('data-id'),
            id_right: $(this).attr('data-id'),
            left_node: _selectFirst,
            right_node: this,
            horizantal_gap: 10,
            error: 'show',
            width: 1,
            status: 'accepted'
          });
          $(_selectFirst).attr('data-use', 'false');
          $(_selectFirst).attr('data-connect', 'true');
          $(this).attr('data-use', 'false');
          $(this).attr('data-connect', 'true');
        }
      }
    });

    this.redrawLines = function() {
      _ctx.clearRect(0, 0, $(_me).width(), $(_me).height());
      _lines.forEach(function(entry) {
        entry.resize = true;
        _me.connect(entry);
      });
    };
    return this;
  };
}(jQuery));
.clearfix {
  clear: both;
}

body {
  padding: 0px;
  margin: 0px;
}

.nodes {
  width: 500px
}

.node {
  width: 100px;
  background: #ddd;
  color: #fff;
  margin-bottom: 10px;
}

.group1 span {
  background: #666;
  border-radius: 50%;
  width: 10px;
  height: 10px;
  margin-top: 5px;
}

.group2 span {
  border: 1px solid #666;
  border-radius: 50%;
  width: 10px;
  height: 10px;
  margin-top: 5px;
}

.node span:hover {
  background: #ff0000;
  cursor: pointer;
}

.group1 {
  float: left;
}

.group2 {
  float: right;
}

.group2 .node span {
  float: left;
  position: relative;
  left: -15px;
}

.group1 .node span {
  float: right;
  position: relative;
  right: -15px;
}

.node span[data-connect=true] {
  background: #ff00ff !important;
}

.node span[data-use=true] {
  background: #ff0000 !important;
}
<div id="parentNodes_11">
  <div class="nodes">
    <div class="group1">
      <div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
      <div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
      <div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
    </div>
    <div class="group2">
      <div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
      <div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
      <div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
    </div>
    <div class="clearfix"></div>
  </div>
</div>
<br>
<div id="parentNodes_12">
  <div class="nodes">
    <div class="group1">
      <div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
      <div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
      <div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
    </div>
    <div class="group2">
      <div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
      <div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
      <div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
    </div>
    <div class="clearfix"></div>
  </div>
</div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script type="text/javascript">
  $(document).ready(function() {
    $('#parentNodes_11 .nodes').connect('#parentNodes_11');
    $('#parentNodes_12 .nodes').connect('#parentNodes_12');
  });
</script>
like image 108
Paul WWJD Avatar answered Jun 03 '26 04:06

Paul WWJD