Get Viewport Lines and Columns in CodeMirror

By  on  

CodeMirror is an amazing utility for presenting code in a browser environment.  Syntax highlighting, widgets, and a number of advanced functions make it a unique, useful tool.  When using CodeMirror inside the Firefox DevTools debugger, I found that adding hundreds of column breakpoint widgets to very long lines of code really killed performance, and I sure as hell can't give you all a horrible experience while you're debugging your JavaScript.

I wanted to get fancy to ensure performance was good, so I decided to tinker around with only displaying column breakpoint widgets that appeared in the viewport.   To do that, I needed to calculate the start line, start column, end line, and end column of the CodeMirror editor's contents, some of which didn't appear to be provided within methods of CodeMirror.

My experimentation led to me to a solution I'm quite happy with; the code is clean, the performance is good, and the method has been incredibly reliable.  Here it is:

function getLocationsInViewport(editor) {
  const charWidth = editor.defaultCharWidth();
  const scrollArea = editor.getScrollInfo();
  const { scrollLeft } = editor.doc;
  const rect = editor.getWrapperElement().getBoundingClientRect();

  const topVisibleLine = editor.lineAtHeight(rect.top, "window");
  const bottomVisibleLine = editor.lineAtHeight(
    rect.bottom,
    "window"
  );

  const leftColumn = Math.floor(scrollLeft > 0 ? scrollLeft / charWidth : 0);
  const rightPosition = scrollLeft + (scrollArea.clientWidth - 30);
  const rightColumn = Math.floor(rightPosition / charWidth);
   return {
    start: {
      line: topVisibleLine,
      column: leftColumn
    },
    end: {
      line: bottomVisibleLine,
      column: rightColumn
    }
  };
}

CodeMirror does provide easy methods for getting the start and end lines in viewport (lineAtHeight) but there's not a similar functionality for column. I opted to get the scrollLeft position of CodeMirror's scroller, then use the default character width and other dimensions to get the approximate column at that position.  My user testing found this method to be very reliable, either at the exact character or one character off (likely due to subpixel math).

I've never proclaimed to be the best developer in the world (I'm far from it) but being clever to find solutions to interesting problems is something that I've always been proud of.

Recent Features

  • By
    LightFace:  Facebook Lightbox for MooTools

    One of the web components I've always loved has been Facebook's modal dialog.  This "lightbox" isn't like others:  no dark overlay, no obnoxious animating to size, and it doesn't try to do "too much."  With Facebook's dialog in mind, I've created LightFace:  a Facebook lightbox...

  • By
    How I Stopped WordPress Comment Spam

    I love almost every part of being a tech blogger:  learning, preaching, bantering, researching.  The one part about blogging that I absolutely loathe:  dealing with SPAM comments.  For the past two years, my blog has registered 8,000+ SPAM comments per day.  PER DAY.  Bloating my database...

Incredible Demos

  • By
    Create Twitter-Style Dropdowns Using MooTools

    Twitter does some great stuff with JavaScript. What I really appreciate about what they do is that there aren't any epic JS functionalities -- they're all simple touches. One of those simple touches is the "Login" dropdown on their homepage. I've taken...

  • By
    Build a Toggling Announcement Slider Using MooTools 1.2

    A few of my customer have asked for me to create a subtle but dynamic (...I know...) way for them to advertise different specials on their website. Not something that would display on every page, but periodically or only the homepage. Using a trick...

Discussion

    Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!