Skip to content

Instantly share code, notes, and snippets.

@ondrek
Created January 28, 2014 13:30
Show Gist options
  • Save ondrek/8667644 to your computer and use it in GitHub Desktop.
Save ondrek/8667644 to your computer and use it in GitHub Desktop.
Canvas Implementation
goog.provide( "lib.display.CanvasText" );
goog.require( "lib.display.IDisplayObject" );
goog.require( "lib.display.CanvasSprite" );
goog.require( "goog.dom" );
goog.require( "goog.events.Event" );
goog.require( "goog.asserts" );
goog.require( "easy.data.domain.placeholder.font.FontStyle" );
goog.require( "goog.math.Coordinate" );
goog.require( "easy.data.domain.Color" );
/**
* @constructor
* @extends {lib.display.CanvasSprite}
*
* @param {goog.math.Coordinate} coordinates
* @param {number} aWidth width of this sprite
* @param {number} aHeight width of this sprite
*
* @param {boolean=} isWrapped
* @param {number=} wrappingSize
* @param {string=} text
* @param {easy.data.domain.placeholder.font.FontStyle=} fontStyle
* @param {easy.data.domain.Color=} fontColor
* @param {number=} fontSize
* @param {string=} font
*
*/
lib.display.CanvasText = function( coordinates, aWidth, aHeight, text, isWrapped, wrappingSize, fontStyle, fontColor, fontSize, font )
{
goog.base( this, coordinates.x, coordinates.y, aWidth, aHeight );
this._width = aWidth;
this._height = aHeight;
this._textPosX = this.getX();
this._textPosY = this.getY();
if (fontStyle) {
this.setFontStyle(fontStyle);
} else {
this.setFontStyle( new easy.data.domain.placeholder.font.FontStyle(false, false, false) );
}
if (fontColor) {
this.setFontColor(fontColor);
} else {
this.setFontColor( new easy.data.domain.Color("000") );
}
if (fontSize) {
this.setFontSize(fontSize);
} else {
this.setFontSize(14);
}
if (font) {
this.setFont(font);
} else {
this.setFont("Arial");
}
if (text) {
this.setText(text);
} else {
this.setText("");
}
this.setPadding(0);
this.setRotation(0);
// TODO : wrapping size subtract text coordinates from object width and height
// (i.e. text x at 10 and text y at 10 should subtract 20px from width and 20px from height)
// (like CSS margin/padding)
this._isWrapped = (isWrapped===undefined) ? true : isWrapped;
this.setWrappingSize( wrappingSize ? wrappingSize : aWidth );
this.setLineHeight(this._fontSize*1.3);
// this is by default false
this.listenToMouseWheel = true;
this.listenToDoubleClick = true;
// ensure we can invoke multiple "handlePress"-events ;)
};
goog.inherits( lib.display.CanvasText, lib.display.CanvasSprite );
/* class constants */
/** @public @type {string} @const */ lib.display.CanvasText.TEXTBASELINE_TOP = "top";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTBASELINE_HANGING = "hanging";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTBASELINE_MIDDLE = "middle";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTBASELINE_ALPHABETIC = "alphabetic";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTBASELINE_IDEOGRAPHIC = "ideographic";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTBASELINE_BOTTOM = "bottom";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTALIGN_START = "start";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTALIGN_END = "end";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTALIGN_LEFT = "left";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTALIGN_CENTER = "center";
/** @public @type {string} @const */ lib.display.CanvasText.TEXTALIGN_RIGHT = "right";
/* private variables */
/** @private @type {number} */ lib.display.CanvasText.prototype._lastClickTime;
/** @private @type {number} */ lib.display.CanvasText.prototype._inputContent;
/** @private @type {string} */ lib.display.CanvasText.prototype._rotation;
/** @private @type {string} */ lib.display.CanvasText.prototype._wrappedText;
/** @private @type {string} */ lib.display.CanvasText.prototype._padding;
/** @private @type {CanvasRenderingContext2D} */ lib.display.CanvasText.prototype._ctx;
/** @private @type {string} */ lib.display.CanvasText.prototype._ctxFont;
/** @private @type {string} */ lib.display.CanvasText.prototype._font;
/** @private @type {easy.data.domain.placeholder.font.FontStyle} */ lib.display.CanvasText.prototype._fontStyle;
/** @private @type {number} */ lib.display.CanvasText.prototype._fontSize;
/** @private @type {easy.data.domain.Color} */ lib.display.CanvasText.prototype._fontColor;
/** @private @type {number} */ lib.display.CanvasText.prototype._lineHeight;
/** @private @type {string} */ lib.display.CanvasText.prototype._text;
/** @private @type {boolean} */ lib.display.CanvasText.prototype._isWrapped;
/** @private @type {boolean} */ lib.display.CanvasText.prototype._isEditing = false;
/** @private @type {number} */ lib.display.CanvasText.prototype._textPosX;
/** @private @type {number} */ lib.display.CanvasText.prototype._textPosY;
/** @private @type {number} */ lib.display.CanvasText.prototype._width;
/** @private @type {number} */ lib.display.CanvasText.prototype._height;
/** @private @type {string} */ lib.display.CanvasText.prototype._textAlign = lib.display.CanvasText.TEXTALIGN_START;
/** @private @type {string} */ lib.display.CanvasText.prototype._textBaseLine = lib.display.CanvasText.TEXTBASELINE_ALPHABETIC;
/** @private @type {number} */ lib.display.CanvasText.prototype._wrappingSize = 500;
/** @private @type {lib.display.Sprite} */ lib.display.CanvasText.prototype._input;
/* public methods */
/**
* @override
* @public
*
* @param {CanvasRenderingContext2D} aCanvasContext
*/
lib.display.CanvasText.prototype.draw = function( aCanvasContext )
{
// aCanvasContext.save(); // save currently rendered canvas content
// aCanvasContext.rotate( this.getRotation() ); // rotate to match text angle
// TODO : text should be rotated from the center, this translation should be at center of this Object ;)
// aCanvasContext.translate( this._bounds.width / 2, this._bounds.height / 2 );
// actual text rendering
aCanvasContext.fillStyle = this._fontColor.getHexValue();
aCanvasContext.font = this._ctxFont;
aCanvasContext.textBaseline = this._textBaseLine;
aCanvasContext.textAlign = this._textAlign;
this._drawText( aCanvasContext );
this._drawMask( aCanvasContext );
this._setBorder( aCanvasContext );
// restore context to previous state
// aCanvasContext.restore();
// TODO: should be inside rotated context ;)
// this._setBorder( aCanvasContext );
};
/**
* @public
*/
lib.display.CanvasText.prototype.createInput = function()
{
if ( goog.DEBUG )
{
goog.asserts.assert( this.stage,
"cannot create Input for CanvasText, it is not added to a StageCanvas" );
goog.asserts.assert( this.stage.getElement().parentNode,
"cannot create Input for CanvasText, its StageCanvas is not in the DOM yet" );
}
var parent = /** @type {Element} */ ( this.stage.getElement().parentNode );
if ( !this._input )
{
var input = this._input = new lib.display.Sprite( goog.dom.TagName.TEXTAREA );
input.addClass( "click-handler" );
// input.addEventListener( goog.events.EventType.KEYDOWN, goog.bind( this.handleTyping, this ));
input.addEventListener( goog.events.EventType.KEYUP , goog.bind( this.handleTyping, this ));
}
// after doubleclick on stage canvas run displayTextarea
// NO, StageCanvas has multiple children, adding a listener to a parent that only applies
// to a single child, is bad practice, override "handleInteraction"-method instead!
// this.stage.addEventListener( goog.events.EventType.CLICK , goog.bind( this.displayTextarea, this ));
// stupid way to align initial offsets ;)
this.setX( this.getX() );
this.setY( this.getY() );
parent.appendChild( this._input.getElement() );
};
/**
* @public
*/
lib.display.CanvasText.prototype.handleTyping = function( aEvent )
{
this.setText( this._input.getElement().value);
};
/**
* @public
*/
lib.display.CanvasText.prototype.displayTextarea = function( aEvent )
{
console.log("hello", aEvent);
};
/**
* @public
* @param {CanvasRenderingContext2D} aCanvasContext
*/
lib.display.CanvasText.prototype._setBorder = function( aCanvasContext )
{
// http://diveintohtml5.info/canvas.html#paths
// scroll to ASK PROFESSOR MARKUP: Why did you start x and y at 0.5? Why not 0?;
var movedX = this.getX() - 0.5 - this._padding/2;
var movedY = this.getY() - 0.5 - this._padding/2;
aCanvasContext.beginPath();
aCanvasContext.moveTo( movedX, movedY );
aCanvasContext.lineTo( movedX, movedY + this._height );
aCanvasContext.lineTo( movedX + this._width, movedY + this._height );
aCanvasContext.lineTo( movedX + this._width, movedY );
aCanvasContext.lineTo( movedX, movedY);
aCanvasContext.lineWidth = 1;
aCanvasContext.strokeStyle = '#f00';
aCanvasContext.stroke();
};
/**
* @public
* @param {CanvasRenderingContext2D} aCanvasContext
*/
lib.display.CanvasText.prototype._drawMask = function( aCanvasContext )
{
aCanvasContext.globalCompositeOperation = 'destination-in';
// +/- 1 because we want display also out-of-bounce border
aCanvasContext.fillRect(
this.getX() - 1,// - this._padding/2,
this.getY() - 1,// - this._padding/2,
this._width + 1,
this._height + 1
);
aCanvasContext.globalCompositeOperation = 'source-over';
};
/**
* @public
* @param {string} newText
* @param {boolean=} isWrapped
* @param {number=} wrapSize
*/
lib.display.CanvasText.prototype.setText = function( newText, isWrapped, wrapSize )
{
this._text = newText;
};
/**
* @public
* @return {string}
*/
lib.display.CanvasText.prototype.getText = function()
{
return this._text;
};
/**
* @public
*/
lib.display.CanvasText.prototype.clearText = function()
{
this._text = "";
};
/**
* @public
* @return {boolean}
*/
lib.display.CanvasText.prototype.hasText = function()
{
return (this._text.length>0);
};
/**
* @public
* @param {easy.data.domain.placeholder.font.FontStyle} fontStyle
*/
lib.display.CanvasText.prototype.setFontStyle = function( fontStyle )
{
// todo implement own underline
var newFontStyle = "";
if (!fontStyle.italic && !fontStyle.bold && !fontStyle.underline) {
newFontStyle += "normal";
}
if (fontStyle.bold) {
newFontStyle += " bold";
}
if (fontStyle.italic) {
newFontStyle += " italic";
}
if (fontStyle.underline) {
// newFontStyle += " underline";
}
this._fontStyle = newFontStyle;
this._ctxFont = this._fontStyle + " " + this._fontSize + "px " + this._font;
};
/**
* @private
*
lib.display.CanvasText.prototype._underlineText = function(context, x, y)
{
// this should be commented now, it's broken
// new version in CanvasText-2.js
var textUnderline = function(context,text,x,y,color,textSize,align){
var textWidth = context.measureText(text).width;
var startX = 0;
var startY = y + (parseInt(textSize)/15);
var endX = 0;
var endY = startY;
var underlineHeight = parseInt(textSize)/15;
if (underlineHeight < 1){
underlineHeight = 1;
}
context.beginPath();
if (align == "center"){
startX = x - (textWidth/2);
endX = x + (textWidth/2);
} else if (align == "right"){
startX = x-textWidth;
endX = x;
} else {
startX = x;
endX = x + textWidth;
}
context.strokeStyle = color;
context.lineWidth = underlineHeight;
context.moveTo(startX,startY);
context.lineTo(endX,endY);context.strokeStyle = "blue";
context.stroke();
};
// Initialize the variables with the required data
var text = "Hello Igor!!";
var textAlign = "center";
var textColor = "blue";
var fontSize = "15px";
var fontFamily = "Calibri";
// Set the canvas context properties
context.font = fontSize + " " + fontFamily;
context.textAlign = textAlign;
context.fillStyle = textColor;
// Display the text on canvas
context.fillText( text, x, y );
// Call the function to underline the text
// We need to pass some values to our function so that it can perform the necessary calculations.
textUnderline( context, text, x, y, textColor, fontSize, textAlign );
};
*/
/**
* @public
* @return {string}
*/
lib.display.CanvasText.prototype.getFontStyle = function()
{
return this._fontStyle;
};
/**
* @public
* @param {string} font
*/
lib.display.CanvasText.prototype.setFont = function( font )
{
this._font = font;
this._ctxFont = this._fontStyle + " " + this._fontSize + "px " + this._font;
};
/**
* @public
* @return {string}
*/
lib.display.CanvasText.prototype.getFont = function()
{
return this._font;
};
/**
* @public
* @param {easy.data.domain.Color} color
*/
lib.display.CanvasText.prototype.setFontColor = function( color )
{
this._fontColor = color;
};
/**
* @public
* @return {easy.data.domain.Color}
*/
lib.display.CanvasText.prototype.getFontColor = function()
{
return this._fontColor;
};
/**
* @public
* @param {number} lineHeight
*/
lib.display.CanvasText.prototype.setLineHeight = function( lineHeight )
{
this._lineHeight = lineHeight;
};
/**
* @public
* @return {number}
*/
lib.display.CanvasText.prototype.getLineHeight = function()
{
return this._lineHeight;
};
/**
* @public
* @param {number} fontSize
*/
lib.display.CanvasText.prototype.setFontSize = function( fontSize )
{
this._fontSize = fontSize;
this._ctxFont = this._fontStyle + " " + this._fontSize + "px " + this._font;
};
/**
* @public
* @return {number}
*/
lib.display.CanvasText.prototype.getFontSize = function()
{
return this._fontSize;
};
/**
* @public
* @param {number} degrees
*/
lib.display.CanvasText.prototype.setRotation = function( degrees )
{
this._rotation = (Math.PI / 180) * degrees;
};
/**
* @public
* @return {number}
*/
lib.display.CanvasText.prototype.getRotation = function()
{
return this._rotation;
};
/**
* @public
* @param {number} wrappingSize
*/
lib.display.CanvasText.prototype.setWrappingSize = function( wrappingSize )
{
this._wrappingSize = wrappingSize;
};
/**
* @public
* @return {number}
*/
lib.display.CanvasText.prototype.getWrappingSize = function()
{
return this._wrappingSize;
};
/**
* @public
* @param {number} padding
*/
lib.display.CanvasText.prototype.setPadding = function( padding )
{
this._padding = padding;
//this.setX( this.getX()+(this._padding/2) );
//this.setY( this.getY()+(this._padding/2) );
//this._wrappingSize = this._wrappingSize - this._padding;
};
/**
* @public
* @return {number}
*/
lib.display.CanvasText.prototype.getPadding = function()
{
return this._padding;
};
/**
* @override
* @public
* @param {number} aValue
lib.display.CanvasText.prototype.setX = function( aValue )
{
goog.base( this, "setY", aValue ); // super call
if ( this._input ) {
this._input.setStyle( "left", aValue + "px" );
}
};*/
/**
* @override
* @public
* @param {number} aValue
lib.display.CanvasText.prototype.setY = function( aValue )
{
goog.base( this, "setY", aValue ); // super call
if ( this._input ) {
this._input.setStyle( "top", aValue + "px");
}
};*/
/**
* @public
* @param {string} alignment
*/
lib.display.CanvasText.prototype.setTextAlign = function( alignment )
{
( goog.DEBUG ) && goog.asserts.assert(
[
lib.display.CanvasText.TEXTALIGN_START,
lib.display.CanvasText.TEXTALIGN_END,
lib.display.CanvasText.TEXTALIGN_LEFT,
lib.display.CanvasText.TEXTALIGN_CENTER,
lib.display.CanvasText.TEXTALIGN_RIGHT
].indexOf( alignment ) > -1,
"Sorry, but a alignment on setTextAlign must have valid HTML5 value"
);
this._textAlign = alignment;
};
/**
* @public
* @return {string}
*/
lib.display.CanvasText.prototype.getTextAlign = function()
{
return this._textAlign;
};
/**
* @public
* @param {string} textBaseLine
*/
lib.display.CanvasText.prototype.setTextBaseline = function( textBaseLine )
{
( goog.DEBUG ) && goog.asserts.assert(
[
lib.display.CanvasText.TEXTBASELINE_TOP,
lib.display.CanvasText.TEXTBASELINE_HANGING,
lib.display.CanvasText.TEXTBASELINE_MIDDLE,
lib.display.CanvasText.TEXTBASELINE_ALPHABETIC,
lib.display.CanvasText.TEXTBASELINE_IDEOGRAPHIC,
lib.display.CanvasText.TEXTBASELINE_BOTTOM
].indexOf( textBaseLine ) > -1,
"Sorry, but a baseline on setTextBaseline must have valid HTML5 value"
);
this._textBaseLine = textBaseLine;
};
/**
* @public
* @return {string}
*/
lib.display.CanvasText.prototype.getTextBaseline = function()
{
return this._textBaseLine;
};
/**
* @private
* @param {CanvasRenderingContext2D} aCanvasContext
*/
lib.display.CanvasText.prototype._drawText = function( aCanvasContext )
{
window.linepositions = [];
window.datas = [];
var lineHeight = this.getLineHeight();
var fontSize = this.getFontSize();
var textPositionX = this.getX() + this._textPosX;
var textPositionY = this.getY() + this._textPosY;
if (this._isWrapped) {
this._wrappedText = this.wordWrappedText( aCanvasContext );
this._wrappedText.forEach(function(row, i){
window.linepositions.push( i*lineHeight+fontSize+textPositionY + " > " + row );
window.datas.push( { i : i, lineHeight : lineHeight, fontSize: fontSize, textPositionY : textPositionY } );
aCanvasContext.fillText(row, textPositionX, i*lineHeight+fontSize+textPositionY);
});
} else {
aCanvasContext.fillText(this._text, textPositionX, textPositionY+lineHeight+fontSize);
}
};
/**
* Returns an array of strings representing the text with line-breaks as it should
* be rendered considering the available width and the font rendering settings on the canvas object.
* Each entry in the array is a final string that should be rendered. This is necessary since there
* is no automatic word-wrapping for text rendering methods on canvas.
*
* @private
*
* @param {CanvasRenderingContext2D} aCanvasContext
*
* @return {Array}
*/
lib.display.CanvasText.prototype.wordWrappedText = function( aCanvasContext )
{
var maxWidth = this._wrappingSize;
var EXPLICIT_NEW_LINE = {}; // Dummy object to represent line breaks
var nextBlock;
var evaluatedWidth = 0;
var blocks = _getWordBlocks(this._text);
function _getWordBlocks( originalText ){
// each word is one block
var allWords = [];
// Break down the original string into blocks by explicit line breaks first, as they take precedence
var EXPLICITLINE_REGEXP = /[\n]/;
var newLineBlocks = originalText.split(EXPLICITLINE_REGEXP);
// every newLineBlocks cut into separated words
while (newLineBlocks.length > 0)
{
var processedBlock = newLineBlocks.shift();
var WHITESPACE_REGEXP = /[\s]/;
var splitProcessedBlock = processedBlock.split(WHITESPACE_REGEXP);
while (splitProcessedBlock.length > 0)
{
allWords.push(splitProcessedBlock.shift());
}
allWords.push(EXPLICIT_NEW_LINE);
}
return allWords;
}
// By this point we will have an array of single words (by white-space) and explicitly placed line breaks.
// Now we can start assessing the non-explicitly broken sequences of words by length and adding more line-break markers as needed.
// Start the assessment by beginning the evaluation with the first entry in the list
var portion = blocks.shift();
var result = [];
while (blocks.length > 0)
{
evaluatedWidth = aCanvasContext.measureText(portion);
if (evaluatedWidth.width > maxWidth) // only if width is smaller than word length
{
// Break by letters before proceeding further
var letterBreaks = this.breakByLettersIfNecessary(aCanvasContext, portion, maxWidth);
while (letterBreaks.length > 0)
{
portion = letterBreaks.shift();
if (letterBreaks.length > 0) result.push(portion);
}
}
nextBlock = blocks.shift();
var skipLine = false;
if (nextBlock == EXPLICIT_NEW_LINE)
{
skipLine = true;
}
else
{
// Measure the upcoming text line
evaluatedWidth = aCanvasContext.measureText(portion + " " + nextBlock);
if (evaluatedWidth.width > maxWidth)
{
skipLine = true;
}
}
if (skipLine)
{
// Text line was deemed to be implicitly broken
// Add the text we've gathered so far as a valid line
if (portion != "" || nextBlock == EXPLICIT_NEW_LINE)
{
result.push(portion);
}
// If there was no explicit line break, the part of text that was not eventually added to the line becomes the beginning of a new line
if (nextBlock != EXPLICIT_NEW_LINE)
{
portion = nextBlock;
}
else
{
// If text was explicitly broken, the new line begins as empty
portion = "";
}
}
else
{
// Text can continue, add the assessed portion to the line compilation and continue
portion += ((portion == "" ? "" : " ") + nextBlock);
}
}
// Add the remainder as the last entry, if it's a valid one. Usually an empty string is a result of splitting
// a string when the result is just a single entry; an empty string is added as a second array entry in this case.
if (portion != "")
{
result.push(portion);
}
return result;
};
/**
* Check the size of the text as solid text line and break it by letter if necessary.
* If a single-entry array is returned, there was no letter break.
*
* @param {CanvasRenderingContext2D} aCanvasContext
* @param {string} text
* @param {number} maxWidth
*
* @return {Array}
*/
lib.display.CanvasText.prototype.breakByLettersIfNecessary = function ( aCanvasContext, text, maxWidth )
{
var result = [];
// Measure the existing line - it can be too long already
var evaluatedWidth = aCanvasContext.measureText(text);
if (evaluatedWidth.width > maxWidth)
{
// The text so far is already too long, break by letters
var brokenByLetter = [];
var currentLine = "";
for (var i = 0; i < text.length - 1; i++)
{
if (currentLine.length == 0) currentLine = text.charAt(i);
evaluatedWidth = aCanvasContext.measureText(currentLine + text.charAt(i + 1));
if (evaluatedWidth.width > maxWidth)
{
brokenByLetter.push(currentLine);
currentLine = text.charAt(i + 1);
}
else
{
currentLine += text.charAt(i + 1);
}
}
// Add the remaining portion as the last item, which should be picked for evaluation later
brokenByLetter.push(currentLine);
// Integrate the letter-broken parts into the result
while (brokenByLetter.length > 0)
{
result.push(brokenByLetter.shift());
}
}
else
{
result.push(text);
}
return result;
};
/* protected methods */
/**
* detect clicked character
*
* @override
*
* @param {number} aXPosition
* @param {number} aYPosition
*/
lib.display.CanvasText.prototype.detectClickedCharacter = function( aXPosition, aYPosition )
{
// var lineNumber = ( aYPosition / this.getLineHeight() ) + this.getFontSize();
// lineNumber = Math.round(lineNumber);
var lineNumber = ( aYPosition / this.getLineHeight() ) - this.getY() + this._textPosY;// + this._fontSize;
//lineNumber -= 13;
lineNumber = Math.ceil( lineNumber );
// i * this.getLineHeight() + this.getX() + this._textPosX + this._fontSize
console.log( "aYPosition", aYPosition, "this.getLineHeight()", this.getLineHeight(), "this.getFontSize()", this.getFontSize() );
console.log( "lineNumber ", lineNumber );
};
/**
* press handler, invoked by the "handleInteraction"-method
* this method will delegate drag and click logic
*
* @override
* @protected
*
* @param {number} aXPosition
* @param {number} aYPosition
*/
lib.display.CanvasText.prototype.handlePress = function( aXPosition, aYPosition )
{
this.detectClickedCharacter( aXPosition, aYPosition );
if ( this._lastClickTime ) {
// if not dragging && less < 300ms && alredy first clicked
var isLessThan300ms = ( +new Date() - this._lastClickTime ) < 300;
if ( isLessThan300ms ) {
// set state to true - used in disabling dragging, interaction, etc..
this._isEditing = true;
// run editing mode, display text area and place text cursor
this.editingMode(true);
}
// again reset double-click functionality to prevent a triple-click
this._lastClickTime = null;
}
else
{
// no timed boolean set >
// create timeout for timedboolean (which should be set to false when timeout passes)
this._lastClickTime = +new Date();
}
// do default behaviour
goog.base( this, "handlePress", aXPosition, aYPosition );
};
/**
* run this function after double clicks
*
* @public
*
* @param {boolean} status
*
*/
lib.display.CanvasText.prototype.editingMode = function( status )
{
// TODO
// display textarea with css class
// detect cursor position
// put a text cursor on correct position
if (status===true) {
console.log( ">> logging: true " );
// add class, in css is defined display:none to display:block
this._input.addClass( "visible" );
// set content of textare before editing on demain
this._input.getElement().value = this.getText();
// focus textarea, doesnt work on mobile devices where needs to be extended functionality
this._input.getElement().focus();
// listen on click and after to second click
this._input.addEventListener( goog.events.EventType.KEYUP, goog.bind( function(e){
// is ESC pressed, text editing should be finished
if (e.keyCode===27) {
this._isEditing = false;
this.editingMode(false);
}
}, this ));
} else {
console.log( ">> logging: off " );
this._input.removeClass( "visible" );
// set to inner content new value on escape
this.setText( this._input.getElement().value );
}
};
/**
* move handler, invoked by the "handleInteraction"-method
* this method will delegate drag logic
*
* @override
* @protected
*
* @param {number} aXPosition
* @param {number} aYPosition
*/
lib.display.CanvasText.prototype.handleMove = function( aXPosition, aYPosition )
{
// when we are dragging a ctx, we don't want to care about doubleclick
this._lastClickTime = null;
if ( !this._isEditing ) {
// not editing ? use default behaviour
goog.base( this, "handleMove", aXPosition, aYPosition );
}
};
/**
*
* as text has both Object bounds and wrapped text bounds
* we override the default mouse wheel handler! =o !!
*
* in other words the restriction of the wheel movement
* comes from the Object bounds, not some parent constraint !
*
* @override
* @protected
* @param {goog.events.Event} aEvent
*/
lib.display.CanvasText.prototype.handleWheelScroll = function( aEvent )
{
var browserEvent = aEvent.getBrowserEvent();
var delta = 0;
var multiplier = 0.3; // lower the speed ;)
// positive number is moving up, negative number is moving down
if ( browserEvent.wheelDelta ) {
delta = browserEvent.wheelDelta;
}
else if ( browserEvent.detail ) {
delta = browserEvent.detail * -120; // Opera / FireFox
}
var targetY = this._textPosY + ( delta * multiplier );
// keep within bounds
var sizeOfText = this._wrappedText.length * (this.getLineHeight());
if ( targetY > this._bounds.top ) {
// targetY = this._bounds.top;
return;
}
else if ( targetY <= -( sizeOfText - this._bounds.height ))
{
return;
//targetY = this._bounds.top + this._bounds.height;
} else if (targetY > 10 ) {
// console.log("bitch!");
return;
}
this._textPosY = targetY;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment