Skip to main content
Enas Abosaefan
Participating Frequently
December 13, 2022
Answered

Finding the coordinates of a given letter using html5 canvas

  • December 13, 2022
  • 3 replies
  • 2373 views

hi,

in flash cs using as3 to find the position of a character we used getCharBoundaries(index).x is it possible to find a character of a label.innerHTML using adobe animate html5 canvas?? thanks.

    This topic has been closed for replies.
    Correct answer kglad

    if you can color the letter also using text field no proplem to use text 


    create a movieclip that contains a textfield.  right align the text if you're going to use right-to-left language like arabic, left align the text for left-to-right languages.  assign the textfield an instance name, eg tf.  assign the movieclip a linkage id, eg tf_mc.

     

    your can then use:

     

    // [word or phrase to be display, character index where bin should be placed for a correct answer]var wordA = [["first word",2],["second word",5]];
    var index,i,mc;

     

    // add your drag and drop listeners. bind(this) to all function calls.

    // sample drop listener function dropF() is below.

     

     

    step1F.bind(this)();

    function step1F(){
    if(!index){
    index = 0;
    } else {
    index++;
    }
    if(wordA.length==index){
    endF();
    } else {
    step2F.bind(this)();
    }
    }
    function step2F(){
    var startX = 0;
    for(i=0;i<wordA[index][0].length;i++){
    mc = new lib.tf_mc();
    mc.name= "mc_"+i
    mc.tf.text = wordA[index][0].charAt(i);
    if(i==wordA[index][1]){
    mc.tf.color = "#00ff00";
    mc.name = "selected_"+i;
    } else {
    mc.tf.color = "#000000";
    mc.name= "mc_"+i
    }
    mc.x = startX;

    // below for right-to-left
    startX -= mc.getBounds().width;

    // below for left-to-right
    // startX += mc.getBounds().width;
    this.p.addChild(mc);
    }
    }
    function dropF(){
    for(i=0;i<wordA[index][0].length;i++){
    if(this.bin.hitTest(this.p.getChildAt(i))){
    if(this.p.getChildAt(i).name.indexOf("selected")>-1){
    correctF.bind(this)();
    } else {
    incorrectF.bind(this)();
    }
    }
    }
    }
    function correctF(){
    // do whatever. when ready for next word/phrase execute cleanF.bind(this)()
    }
    function incorrectF(){
    // do whatever else. when ready for next word/phrase execute cleanF.bind(this)()
    }

    function cleanF(){
    for(i=this.p.numChildren;i>=0;i--){
    this.p.removeChildAt(i);
    }
    step1F.bind(this)()
    }
    function endF(){
    // game over
    }

    3 replies

    JoãoCésar17023019
    Community Expert
    Community Expert
    December 22, 2022

    Hi.

     

    This is just a suggestion that I hope will help you to get started.

     

    It doesn't work perfectly with arabic texts unfortunately. This is because in arabic texts two (or more?) letters are usually combined together and this makes the calculations very hard.

     

    Special characters may overflow as well.

     

    It's not the most efficient way of doing this and also the bounding boxes will need some workaround to remain invisible.

     

    Again, I just want to provide a sample of what it is possible by only using the CreateJS API. Maybe it's possible to do more using the canvas API.

     

    Try it:
    https://bit.ly/3WEJHtm

     

    Javascript&colon;

    [Global script]:

    (function()
    {
    	window.ui = {};
    
    	// text boxes
    	ui.TextBoxes = function(target)
    	{
    		this.target = target;
    		this.setBoundingBoxes();
    	}
    
    	ui.TextBoxes.prototype.setBoundingBoxes = function()
    	{
    		var originalText = this.target.text;
    		var originalMetrics = this.target.getMetrics();
    		var currentWidth = originalMetrics.width;
    		var lines = originalMetrics.lines;
    		var totalLines = lines.length;
    		var lettersWidthSum = 0;
    		var totalLinesLetters, letterMetrics, i, j;
    		var boundingBox = {};	
    		var alignOffset = this.getAlignmentOffset(this.target);
    		
    		this.target.text = "";
    		this.target.boundingBoxes = [];
    		
    		for (i = 0; i < totalLines; i++)
    		{
    			totalLinesLetters = lines[i].length;
    			lettersWidthSum = 0;
    			this.target.text = lines[i];
    			currentWidth = this.target.getMetrics().width;
    			
    			for (j = 0; j < totalLinesLetters; j++)
    			{
    				this.target.text = lines[i][j];
    				letterMetrics = this.target.getMetrics();
    				boundingBox = this.drawBoundingBox(letterMetrics.width, letterMetrics.height);
    				boundingBox.x = this.target.x + lettersWidthSum - currentWidth * alignOffset;
    				boundingBox.y = this.target.y + letterMetrics.lineHeight * i;
    				boundingBox.setBounds(boundingBox.x, boundingBox.y, letterMetrics.width, letterMetrics.height);
    				boundingBox.alpha = 0.2;
    				boundingBox.tf = this.target;
    				this.target.parent.addChild(boundingBox);
    				lettersWidthSum += letterMetrics.width;
    				this.target.boundingBoxes.push(boundingBox);
    			}
    		}
    
    		this.target.text = originalText;
    	};
    
    	ui.TextBoxes.prototype.drawBoundingBox = function(width, height)
    	{
    		var shape = new createjs.Shape();
    		
    		shape.graphics.beginFill("rgba(255,255,255,0.1)");
    		shape.graphics.beginStroke("rgba(255,255,255,1)");
    		shape.graphics.setStrokeStyle(1);
    		shape.graphics.drawRect(0, 0, width, height);
    		shape.graphics.endFill();
    		shape.graphics.endStroke();
    		
    		return shape;
    	}
    
    	ui.TextBoxes.prototype.getAlignmentOffset = function()
    	{
    		if (this.target.textAlign === "left")
    			return 0;
    		
    		if (this.target.textAlign === "center")
    			return 0.5;
    		
    		if (this.target.textAlign === "right")
    			return 1;
    	};
    
    	ui.TextBoxes.prototype.destroy = function()
    	{
    		if (!this.target.boundingBoxes)
    			return;
    		
    		this.target.boundingBoxes.forEach(function(boundingBox)
    		{
    			boundingBox.parent.removeChild(boundingBox);
    			boundingBox._off = true;
    		});
    		
    		delete this.target.boundingBoxes;
    	};
    
    
    	// drag and drop
    	ui.DragAndDrop = function(target, callbacks)
    	{
    		this.target = target;
    		this.callbacks = callbacks || {};
    		this.mouseDownListener = this.target.on("mousedown", this.onMouseDown, this);
    		this.pressMoveListener = this.target.on("pressmove", this.onPressMove, this);
    		this.pressUpListener = this.target.on("pressup", this.onPressUp, this);
    	};
    
    	ui.DragAndDrop.prototype.onMouseDown = function(e)
    	{
    		var pointer = this.getPointer(this.target);
    		
    		this.target.offset = { x: pointer.x - this.target.x, y: pointer.y - this.target.y };
    		this.target.parent.addChild(this.target);
    		
    		if (this.callbacks.onMouseDown)
    			this.callbacks.onMouseDown.call(this);
    	};
    
    	ui.DragAndDrop.prototype.onPressMove = function(e)
    	{
    		var pointer = this.getPointer(this.target);
    		
    		this.target.x = pointer.x - this.target.offset.x;
    		this.target.y = pointer.y - this.target.offset.y;
    		
    		if (this.callbacks.onPressMove)
    			this.callbacks.onPressMove.call(this);
    	};
    
    	ui.DragAndDrop.prototype.onPressUp = function(e)
    	{		
    		if (this.callbacks.onPressUp)
    			this.callbacks.onPressUp.call(this);
    	};
    
    	ui.DragAndDrop.prototype.getPointer = function(target)
    	{
    		return target.parent.globalToLocal(target.stage.mouseX, target.stage.mouseY);
    	};
    
    	ui.DragAndDrop.prototype.destroy = function()
    	{
    		this.target.off("mousedown", this.mouseDownListener);
    		this.target.off("pressmove", this.pressMoveListener);
    		this.target.off("pressup", this.pressUpListener);	
    		
    		delete this.target;
    		delete this.callbacks;
    	};
    })();


    [Frame 0 of main timeline]:

    // the TextBoxes and DragAndDrop classes are located in the globa script section (left sections)
    
    var callbacks =
    {
    	onMouseDown: function()
    	{
    		this.target.mouseEnabled = false;
    	},
    	onPressUp: function()
    	{
    		var box = this.currentBoundingBox;
    		
    		this.target.mouseEnabled = true;
    		
    		if (box && box.correct !== undefined)
    		{
    			drawBoundingBox(box);
    			
    			this.target.x = box.x + box.getBounds().width * 0.5;
    			this.target.y = box.y - this.target.nominalBounds.height * 0.5;
    			
    			box.tf.dragAndDrop.destroy();
    			box.tf.textBoxes.destroy();
    			
    			box = null;
    		}
    		else
    		{
    			this.target.x = this.target.initialX;
    			this.target.y = this.target.initialY;
    		}
    	}
    };
    
    function main()
    {
    	var resetTarget0 = { tf: root.tf0, bin: root.bin0, correct: 1, slot: root.slot0 };
    	var resetTarget1 = { tf: root.tf1, bin: root.bin1, correct: 0, slot: root.slot1 };
    	var resetTarget2 = { tf: root.tf2, bin: root.bin2, correct: 2, slot: root.slot2 };
    
    	setup();
    	setGame(root.tf0, root.bin0, 1, root.slot0);
    	setGame(root.tf1, root.bin1, 0, root.slot1);
    	setGame(root.tf2, root.bin2, 2, root.slot2);
    	root.resetButton0.on("click", onReset, null, false, resetTarget0);
    	root.resetButton1.on("click", onReset, null, false, resetTarget1);
    	root.resetButton2.on("click", onReset, null, false, resetTarget2);
    	root.resetAllButton.on("click", onResetAll, null, false, { targets: [ resetTarget0, resetTarget1, resetTarget2 ] });
    }
    
    function setup()
    {
    	document.body.style.backgroundColor = lib.properties.color;
    	createjs.Touch.enable(stage);
    	stage.enableMouseOver(50);
    	stage.mouseMoveOutside = true;
    	root.stop();
    }
    
    function setGame(tf, bin, correct, slot)
    {
    	tf.textBoxes = new ui.TextBoxes(tf);
    	tf.boundingBoxes[correct].correct = true;
    	
    	tf.boundingBoxes.forEach(function(boundingBox)
    	{
    		boundingBox.mouseOverListener = boundingBox.on("mouseover", onMouseOver);
    		boundingBox.mouseOutListener = boundingBox.on("mouseout", onMouseOut);
    	});
    
    	tf.dragAndDrop = new ui.DragAndDrop(bin, callbacks);
    	bin.initialX = slot.x;
    	bin.initialY = slot.y;
    }
    
    function onMouseOver(e)
    {
    	e.currentTarget.alpha = 1;
    	e.currentTarget.tf.dragAndDrop.currentBoundingBox = e.currentTarget;
    }
    
    function onMouseOut(e)
    {
    	e.currentTarget.alpha = 0.2;
    	e.currentTarget.tf.dragAndDrop.currentBoundingBox = null;
    }
    
    function drawBoundingBox(box)
    {
    	box.tf.winBox = new createjs.Shape();
    	box.tf.winBox.graphics.beginFill("rgba(255,255,255,0.5)");
    	box.tf.winBox.graphics.beginStroke("white");
    	box.tf.winBox.graphics.setStrokeStyle(2);
    	box.tf.winBox.graphics.drawRect(0, 0, box.getBounds().width, box.getBounds().height);
    	box.tf.winBox.graphics.endFill();
    	box.tf.winBox.graphics.endStroke();
    	box.tf.winBox.x = box.x;
    	box.tf.winBox.y = box.y;
    	box.tf.parent.addChild(box.tf.winBox);
    }
    
    function onReset(e, data)
    {
    	if (data.tf.dragAndDrop.target)
    		data.tf.dragAndDrop.destroy();
    	
    	if (data.tf.textBoxes.target)
    		data.tf.textBoxes.destroy();
    	
    	root.addChild(data.bin);
    	data.bin.x = data.slot.x;
    	data.bin.y = data.slot.y;
    	
    	if (data.tf.winBox && data.tf.winBox.parent)
    	{
    		data.tf.winBox.parent.removeChild(data.tf.winBox);
    		data.tf.winBox._off = true;
    	}
    	
    	setGame(data.tf, data.bin, data.correct, data.slot);
    }
    
    function onResetAll(e, data)
    {
    	data.targets.forEach(function(target){ onReset(null, target); });
    }
    
    if (!this.frame0started)
    {
    	window.root = this;
    	main();
    	this.frame0started = true;
    }

     

    Code / FLA / files / source:
    https://bit.ly/3BWEx3S

     

    I hope it helps.

     

    Regards,

    JC

     

    Enas Abosaefan
    Participating Frequently
    December 26, 2022

    thank's alot 🙂

     

    Legend
    December 13, 2022

    Not by any reasonable means, no. If you want the position of an individual character, you have to make the character an individual object.

    Enas Abosaefan
    Participating Frequently
    December 13, 2022

    unfortunately,it's an impractical solution  because there is alot of words inside the website also it's an arabic words the width changed when the letter inside the word or it inside an individual object

    kglad
    Community Expert
    Community Expert
    December 13, 2022

    you're trying to find a letter where?  on stage? 

     

    if so, is it text?

     

    and what's the point?  is this a game?

    Enas Abosaefan
    Participating Frequently
    December 13, 2022

    it's a label on stage

    yes, I want to get rectangle for certain letter inside label innerHTML 

    it's an education website and I want to add hidden bin for the letter inside the word and the child hold the item to match the correct answer

    thank's alot 🙂

    kglad
    Community Expert
    Community Expert
    December 13, 2022

    @Enas Abosaefan 

     

    i'm certain you can accomplish what you want, but i'm not sure you can do it with your current approach.

     

    paste a screenshot of the stage showing what's on it and what you're trying to detect.