Show hidden part of truncated text on hover/touch

Here are three ways to show hidden part of truncated text on touch/hover without Javascript

1) overflow:visible

Hover over or touch me to see the full version of this string. It looks like replaced by tooltip
some other stuff

Pros:

  • No Javascript
  • Good readability
  • Small and simple cross-browser CSS code
  • Easy to render.

Contras:

  • Need extra markup (inner span wrapper)
  • Requires all the parents of the text container to be wide enough or have ‘overflow’ porperty to be ‘visible’.

Here is SCSS with comments:

.overflow-tip {
  /* make it single-line */
  white-space:nowrap;
  /* truncate by container's size */
  overflow-x: hidden;
  /* add three dots */
  text-overflow: ellipsis;
  /* on touch or hover */
  &:active, &:hover {
    /* show hidden part outside of parent */
    overflow-x: visible;
    /* and with inner span */
    span {
      /* allow to overlap siblings */
      position: relative;
      /* make readable design */
      background-color: PaleGoldenRod;
      border: 1px solid gray;
      padding: 3px;
      /* compensate padding and border size to avoid jerking */
      margin-left: -4px;
    }    
  }
}

2) direction:rtl

Hover over or touch me to see the end of this long string.
some other stuff

Pros:

  • No Javascript
  • No extra HTML
  • Super simple CSS

Contras:

  • Not so readable for very long string or very short container
    Commented scss:
.rtl-switch {
  /* make it single-line */
  white-space:nowrap;
  /* truncate by container's size */
  overflow-x: hidden;
  /* add three dots */
  text-overflow: ellipsis;
  /* on touch or hover */
  &:active, &:hover {
    /* make text have right to left direction */
    direction: rtl;
    /* fix three dots overlapping issue*/
    padding-left:10px;
    &:after {
      /* fix brackets in rtl mode */
      content: "\200E‎";
    }
  }
}

3) marquee (transition left)

Hover over or touch me to see animated scrolling of this string. Fancy but buggy. May be still can be improved.
some other stuff

Pros:

1) Fancy
2) Displays whole string in a limited space

Contras:

1) Bloated HTML (needs two extra spans)
2) Bad readability for long strings
3) Animation bug on mouse out or not truncated string(may be still can be fixed, I’ll see later)
4) Animation can load CPU on heavy page
5) Needs hardcoded offset, or will be scrolled until container is not empty
Let’s see some code:

.marquee {
  /* Single line */
  white-space:nowrap;
  /* Truncate by container size */
  overflow: hidden;
  /* Both spans */
  span {
    /* Allow to set size */
    display: inline-block;
    /* Size same as container when not hovered to allow ellipsis */
    width: 100%;
    /* Second span */
    span {
      /* Turn animation on */
      @include transition(left 4s linear);
      /* Allow position manipulation */
      position: relative;
      /* truncate by container's size */
      overflow-x: hidden;
      /* add three dots */
      text-overflow: ellipsis;
      /* Explicitly declare initial position to animate well */
      left: 0px;
    }   
  }
  /* on touch or hover */
  &:active, &:hover {
    /* Both spans */
    span {
      /* resize to contain whole string without truncation. */
      width: auto;
      /* Second span */
      span {
        /* Animated scroll by length of first span (100% of parent),
  which equals to length of string, not a container.
  Also shift final point back by width of container (500px)
  to not finish with empty box
  and pitch by 15px - I don't know why, may be to compensate paddings */
        left:calc(500px - 15px - 100%);//
      }
    }    
  }

Here is a codepen to play:

See the Pen Expand cropped string on hover/touch, pure CSS by Yuri Gor (@yurigor) on CodePen.0

Pan and Zoom in jsPlumb Community Edition with Dagre and jQueryUI Draggable

See the Pen Pan and Zoom in jsPlumb Community Edition with Dagre and jQueryUI Draggable by Yuri Gor (@yurigor) on CodePen.0

Chart with draggable HTML elements as nodes, connected by jsPlumb library.
“Pan&Zoom” feature missing in Comunity Edition implemented by using “jQuery Panzoom” plugin.
Nodes dragging implemented by jQueryUI Draggable, to compensate scale distortion.
Dagre layout library used for demonstration.

I use static predefined html in this example:

<!-- .container - just part of your page,
where you want to render diagram -->
<div class="container">
  <!-- .panzoom - wrapper div, panzoom plugin will transform it.
        Use it for worksheet element styling -->
  <div class="panzoom">
    <!-- .diagram - wrapper div to be used by jsPlumb.
         It will have zero height, so no visual CSS works here. -->
    <div class="diagram">
      <!-- .item - diagram nodes, must have unique id's
           to be able connect them by jsPlumb. -->
      <div id="i0"  class="item">Root</div>
      <div id="i1" class="item">Child 1</div>
      <div  id="i11" class="item">Child 1.1</div>
      <div  id="i12" class="item">Child 1.2</div>
      <div id="i2" class="item">Child 2</div>
      <div id="i21" class="item">Child 2.1</div>
      <div id="i3" class="item">Child 3</div>
    </div>
  </div>
</div>

Links between nodes declared in js array:

var links = [
  { from: "i0", to: "i1" },
  { from: "i1", to: "i11" },
  { from: "i1", to: "i12" },
  { from: "i0", to: "i2" },
  { from: "i2", to: "i21" },
  { from: "i0", to: "i3" },
];

Initializing of panzoom:

$panzoom = $container.find('.panzoom').panzoom({
      minScale: minScale,//0.4
      maxScale: maxScale,//2
      increment: incScale,//0.1
      cursor: "",/*empty string prevents panzoom
          from changing cursor styles defined in your css.*/
    }).on("panzoomstart",function(e,pz,ev){
      $panzoom.css("cursor","move");//set "move" cursor on start only
    })
    .on("panzoomend",function(e,pz){
      $panzoom.css("cursor","");//restore cursor
    });

Mouse wheel support and pan while drag begins outside diagram:

$panzoom.parent()
    .on('mousewheel.focal', function( e ) {
      //if Control pressed then zoom
      if(e.ctrlKey||e.originalEvent.ctrlKey)
      {
        e.preventDefault();
        var delta = e.delta || e.originalEvent.wheelDelta;
        var zoomOut = delta ? delta < 0 : e.originalEvent.deltaY > 0;
        $panzoom.panzoom('zoom', zoomOut, {
           animate: true,
           exponential: false,
        });
      }else{//else pan (touchpad and Shift key works)
        e.preventDefault();
        var deltaY = e.deltaY || e.originalEvent.wheelDeltaY || (-e.originalEvent.deltaY);
        var deltaX = e.deltaX || e.originalEvent.wheelDeltaX || (-e.originalEvent.deltaX);
        $panzoom.panzoom("pan",deltaX/2,deltaY/2,{
          animate: true,
          relative: true,
        });
      }
    })
    //on start store initial offsets and mouse coord
    .on("mousedown touchstart",function(ev){
      var matrix = $container.find(".panzoom").panzoom("getMatrix");
      var offsetX = matrix[4];
      var offsetY = matrix[5];
      var dragstart = {x:ev.pageX,y:ev.pageY,dx:offsetX,dy:offsetY};
      $(ev.target).css("cursor","move");
      $(this).data('dragstart', dragstart);
    })
    //calculate mouse offset from starting pos and apply it to panzoom matrix
    .on("mousemove touchmove", function(ev){
      var dragstart = $(this).data('dragstart');
      if(dragstart)
      {
        var deltaX = dragstart.x-ev.pageX;
        var deltaY = dragstart.y-ev.pageY;
        var matrix = $container.find(".panzoom").panzoom("getMatrix");
        matrix[4] = parseInt(dragstart.dx)-deltaX;
        matrix[5] = parseInt(dragstart.dy)-deltaY;
        $container.find(".panzoom").panzoom("setMatrix",matrix);
      }
    })
    .on("mouseup touchend touchcancel", function(ev){
      $(this).data('dragstart',null);
      $(ev.target).css("cursor","");
    });
  });

Make nodes draggable by jQueryUI/draggable:

var currentScale = 1;
  $container.find(".diagram .item").draggable({
    start: function(e){
      var pz = $container.find(".panzoom");
      //save current scale factor to consider it later
      currentScale = pz.panzoom("getMatrix")[0];
      $(this).css("cursor","move");
      //disable panzoom, to avoid panning while dragging node
      pz.panzoom("disable");
    },
    drag:function(e,ui){
      /*compensate current scale while dragging,
           else pointer and node will have different speeds*/
      ui.position.left = ui.position.left/currentScale;
      ui.position.top = ui.position.top/currentScale;
      //it's possible to have not connected nodes, so let's check it.
      if($(this).hasClass("jsplumb-connected"))
      {
        plumb.repaint($(this).attr('id'),ui.position);
      }
    },
    stop: function(e,ui){
      var nodeId = $(this).attr('id');
      if($(this).hasClass("jsplumb-connected"))
      {
        plumb.repaint(nodeId,ui.position);
      }
      $(this).css("cursor","");
      $container.find(".panzoom").panzoom("enable");
    }
  });