0
点赞
收藏
分享

微信扫一扫

文本光标、行、段落对象53

TextCursor = function (fillStyle, width) {
   this.fillStyle   = fillStyle || 'rgba(0, 0, 0, 0.7)';
   this.width       = width || 2;
   this.left        = 0;
   this.top         = 0;
};

TextCursor.prototype = {
   getHeight: function (context) {
      var w = context.measureText('W').width;
      return w + w/6;
   },
      
   createPath: function (context) {
      context.beginPath();
      context.rect(this.left, this.top,
                   this.width, this.getHeight(context));//实际上是一个矩形
   },
   
   draw: function (context, left, bottom) {
      context.save();

      this.left = left;
      this.top = bottom - this.getHeight(context);

      this.createPath(context);

      context.fillStyle = this.fillStyle;
      context.fill();
         
      context.restore();
   },

   erase: function (context, imageData) {
      context.putImageData(imageData, 0, 0,
         this.left, this.top,
         this.width, this.getHeight(context));
   }
};
/*
    var cursor = new TextCursor();
    cursor.draw(context, loc.x, loc.y);
*/

// Text lines.....................................................

TextLine = function (x, y) {
   this.text = '';
   this.left = x;
   this.bottom = y;
   this.caret = 0;
};

TextLine.prototype = {
   insert: function (text) {
      var first = this.text.slice(0, this.caret),
          last = this.text.slice(this.caret);

      first += text;
      this.text = first;
      this.text += last;
      this.caret += text.length;
   },

   getCaretX: function (context) {
      var s = this.text.substring(0, this.caret),
          w = context.measureText(s).width;

      return this.left + w;
   },
   
   removeCharacterBeforeCaret: function () {
      if (this.caret === 0)
         return;

      this.text = this.text.substring(0, this.caret-1) +
                  this.text.substring(this.caret); 

      this.caret--;
   },

   removeLastCharacter: function () {
      this.text = this.text.slice(0, -1);
   },

   getWidth: function(context) {
      return context.measureText(this.text).width;
   },

   getHeight: function (context) {
      var h = context.measureText('W').width;
      return h + h/6;
   },
   
   draw: function(context) {
      context.save();
      context.textAlign = 'start';
      context.textBaseline = 'bottom';
       
      context.strokeText(this.text, this.left, this.bottom);
      context.fillText(this.text, this.left, this.bottom);

      context.restore();
   },

   erase: function (context, imageData) {
      context.putImageData(imageData, 0, 0);
   }
};

/*
canvas.onmousedown = function (e) {
   var loc = windowToCanvas(e.clientX, e.clientY),
       fontHeight = context.measureText('W').width;

   fontHeight += fontHeight/6;
   line = new TextLine(loc.x, loc.y);
   moveCursor(loc.x, loc.y);
};
document.onkeydown = function (e) {
   if (e.keyCode === 8 || e.keyCode === 13) { e.preventDefault();}
   
   if (e.keyCode === 8) {  // backspace
      context.save();
      line.erase(context, drawingSurfaceImageData);
      line.removeCharacterBeforeCaret();
     // moveCursor(line.left + line.getWidth(context),line.bottom);
      line.draw(context);
      context.restore();
   }
}
   
document.onkeypress = function (e) {
   var key = String.fromCharCode(e.which);
   if (e.keyCode !== 8 && !e.ctrlKey && !e.metaKey) {
     e.preventDefault(); // no further browser processing
     context.save();
     line.erase(context, drawingSurfaceImageData);
     line.insert(key);
     moveCursor(line.left + line.getWidth(context), line.bottom);
     line.draw(context);
     context.restore();
   }
}
*/

// Paragraphs.....................................................
Paragraph = function (context, left, top, imageData, cursor) {
   this.context = context;
   this.drawingSurface = imageData;
   this.left = left;
   this.top = top;
   this.lines = [];
   this.activeLine = undefined;
   this.cursor = cursor;
   this.blinkingInterval = undefined;
};

Paragraph.prototype = {
   isPointInside: function (loc) {//如果给定的点落在段落内,则返回true
      var c = this.context;

      c.beginPath();
      c.rect(this.left, this.top, 
             this.getWidth(), this.getHeight());

      return c.isPointInPath(loc.x, loc.y);
   },
   
   getHeight: function () {
      var h = 0;

      this.lines.forEach( function (line) {
         h += line.getHeight(this.context); 
      });

      return h;
   },
   
   getWidth: function () {
      var w = 0,
          widest = 0;

      this.lines.forEach( function (line) {
         w = line.getWidth(this.context); 
         if (w > widest) {
            widest = w;
         }
      });

      return widest;
   },

   draw: function () {
      this.lines.forEach( function (line) {
         line.draw(this.context);
      });
   },

   erase: function (context, imageData) {
      context.putImageData(imageData, 0, 0);
   },
   
   addLine: function (line) {//向文本段对象中添加一个TextLine对象
      this.lines.push(line);
      this.activeLine = line;
      this.moveCursor(line.left, line.bottom);
   },

   insert: function (text) {//在当前光标处插入文本
     this.erase(this.context, this.drawingSurface);
     this.activeLine.insert(text);

     var t = this.activeLine.text.substring(0, this.activeLine.caret),
         w = this.context.measureText(t).width;
      
     this.moveCursor(this.activeLine.left + w,
                     this.activeLine.bottom);

     this.draw(this.context);
   },

   blinkCursor: function (x, y) {
      var self = this,
          BLINK_OUT = 200,
          BLINK_INTERVAL = 900;

      this.blinkingInterval = setInterval( function (e) {
         cursor.erase(context, self.drawingSurface);
      
         setTimeout( function (e) {
            cursor.draw(context, cursor.left,
                        cursor.top + cursor.getHeight(context));
         }, BLINK_OUT);
      }, BLINK_INTERVAL);
   },

   moveCursorCloseTo: function (x, y) {//给定一组x与y坐标,将光标移动到距其最近的位置
      var line = this.getLine(y);

      if (line) {
         line.caret = this.getColumn(line, x);
         this.activeLine = line;
         this.moveCursor(line.getCaretX(context),
                         line.bottom);
      }
   },
   
   moveCursor: function (x, y) {
      this.cursor.erase(this.context, this.drawingSurface);
      this.cursor.draw(this.context, x, y);

      if ( ! this.blinkingInterval)
         this.blinkCursor(x, y);
   },

   moveLinesDown: function (start) {
      for (var i=start; i < this.lines.length; ++i) {
         line = this.lines[i];
         line.bottom += line.getHeight(this.context);
      }
   },
   
   newline: function () {//在当前光标处执行新行操作
      var textBeforeCursor = this.activeLine.text.substring(0, this.activeLine.caret),
          textAfterCursor = this.activeLine.text.substring(this.activeLine.caret),
          height = this.context.measureText('W').width +
                   this.context.measureText('W').width/6,
          bottom  = this.activeLine.bottom + height,
          activeIndex,
          line;

      this.erase(this.context, this.drawingSurface);     // Erase paragraph
      this.activeLine.text = textBeforeCursor;           // Set active line's text

      line = new TextLine(this.activeLine.left, bottom); // Create a new line
      line.insert(textAfterCursor);                      // containing text after cursor

      activeIndex = this.lines.indexOf(this.activeLine); // Splice in new line
      this.lines.splice(activeIndex+1, 0, line);

      this.activeLine = line;                            // New line is active with
      this.activeLine.caret = 0;                         // caret at first character

      activeIndex = this.lines.indexOf(this.activeLine); // Starting at the new line...

      for(var i=activeIndex+1; i < this.lines.length; ++i) { //...loop over remaining lines
         line = this.lines[i];
         line.bottom += height; // move line down one row
      }

      this.draw();
      this.cursor.draw(this.context, this.activeLine.left, this.activeLine.bottom);
   },

   getLine: function (y) {
      var line;
      
      for (i=0; i < this.lines.length; ++i) {
         line = this.lines[i];
         if (y > line.bottom - line.getHeight(context) &&
             y < line.bottom) {
            return line;
         }
      }
      return undefined;
   },

   getColumn: function (line, x) {
      var found = false,
          before,
          after,
          closest,
          tmpLine,
          column;

      tmpLine = new TextLine(line.left, line.bottom);
      tmpLine.insert(line.text);
         
      while ( ! found && tmpLine.text.length > 0) {
         before = tmpLine.left + tmpLine.getWidth(context);
         tmpLine.removeLastCharacter();
         after = tmpLine.left + tmpLine.getWidth(context);
            
         if (after < x) {
            closest = x - after < before - x ? after : before;
            column = closest === before ?
                     tmpLine.text.length + 1 : tmpLine.text.length;
            found = true;
         }
      }
      return column;
   },

   activeLineIsOutOfText: function () {
      return this.activeLine.text.length === 0;
   },

   activeLineIsTopLine: function () {
      return this.lines[0] === this.activeLine;
   },

   moveUpOneLine: function () {
      var lastActiveText, line, before, after;
      
      lastActiveLine = this.activeLine;
      lastActiveText = '' + lastActiveLine.text;
            
      activeIndex = this.lines.indexOf(this.activeLine);
      this.activeLine = this.lines[activeIndex - 1];
      this.activeLine.caret = this.activeLine.text.length;

      this.lines.splice(activeIndex, 1);
            
      this.moveCursor(
         this.activeLine.left + this.activeLine.getWidth(this.context),
         this.activeLine.bottom);

      this.activeLine.text += lastActiveText;

      for (var i=activeIndex; i < this.lines.length; ++i) {
         line = this.lines[i];
         line.bottom -= line.getHeight(this.context);
      }
   },

   backspace: function () {//在当前光标处执行退格操作
      var lastActiveLine,
          activeIndex,
          t, w;

      this.context.save();

      if (this.activeLine.caret === 0) {
         if ( ! this.activeLineIsTopLine()) {
            this.erase(this.context, this.drawingSurface);
            this.moveUpOneLine();
            this.draw();
         }
      }
      else {  // active line has text
        this.context.fillStyle = fillStyleSelect.value;
         this.context.strokeStyle = strokeStyleSelect.value;

         this.erase(this.context, this.drawingSurface);
         this.activeLine.removeCharacterBeforeCaret();

         t = this.activeLine.text.slice(0, this.activeLine.caret),
         w = this.context.measureText(t).width;
      
         this.moveCursor(this.activeLine.left + w,
                     this.activeLine.bottom);

         this.draw(this.context);

         context.restore();
      }
   }
};

/**
canvas.onmousedown = function (e) {
   var loc = windowToCanvas(canvas, e.clientX, e.clientY),
       fontHeight,
       line;
   cursor.erase(context, drawingSurfaceImageData);
   saveDrawingSurface();
   if (paragraph && paragraph.isPointInside(loc)) {
      paragraph.moveCursorCloseTo(loc.x, loc.y);
   }
   else {
      fontHeight = context.measureText('W').width,
      fontHeight += fontHeight/6;
      paragraph = new Paragraph(context, loc.x, loc.y - fontHeight,
                               drawingSurfaceImageData,
                               cursor);
      paragraph.addLine(new TextLine(loc.x, loc.y));
   }
};

// Key event handlers............................................

document.onkeydown = function (e) {
   if (e.keyCode === 8 || e.keyCode === 13) {
      e.preventDefault();
   }
   
   if (e.keyCode === 8) {  // backspace
      paragraph.backspace();
   }
   else if (e.keyCode === 13) { // enter
      paragraph.newline();
   }
}
   
document.onkeypress = function (e) {
   var key = String.fromCharCode(e.which);

   if (e.keyCode !== 8 && !e.ctrlKey && !e.metaKey) {
     e.preventDefault(); // no further browser processing
     context.fillStyle = fillStyleSelect.value;
     context.strokeStyle = strokeStyleSelect.value;

     paragraph.insert(key);
   }
}
/

举报

相关推荐

0 条评论