OCR using HTML5 canvas - javascript

I'm a complete newbee to HTML5 and Javascript. I'm trying to make this simple app in HTML5 where a user can draw any alphabet on the canvas and the alphabet gets recognized using ocrad.js. However, upon executing this script, no matter what alphabet i draw, the output is always the alphabet 'I'. My guess is that an empty canvas is being passed as an argument to OCRAD or there is an error in linking ocrad.js .
I'm not even sure, how to include the ocrad API as 'src' as i'm completely new to Javascript. Here's what i have written so far.
<canvas id="myCanvas" width="275" height="400" onmouseup="release()" onmousedown="lc=1" onmousemove="Draw(event)" onclick="putPoint(event)" style="border:1px solid #000000;">
</canvas>
<div id="buttons">
<input type="button" id="clear" value="Clear">
</div>
<div id="buttons">
<input type="button" id="recognize" value="Recognize">
</div>
<script src="ocrad.js/ocrad.js"></script>
<script type="text/javascript">
var cnv = document.getElementById('myCanvas')
var ctx = cnv.getContext('2d')
var lc=0
var prX=-1
var prY=-1
var dot= ctx.createImageData(2,2)
for (i=0; i<dot.data.length; i+=4){
dot.data[i+0]=0
dot.data[i+1]=160
dot.data[i+2]=230
dot.data[i+3]=255
}
document.getElementById('clear').addEventListener('click', function() {
ctx.clearRect(0, 0, cnv.width, cnv.height);
}, false);
function release(){
lc=0
prX=-1
}
function putPoint(event){
var bb, x, y
bb = cnv.getBoundingClientRect()
x = (event.clientX-bb.left) * (cnv.width/bb.width)
y = (event.clientY-bb.top) * (cnv.height/bb.height)
ctx.putImageData(dot,x,y)
}
function Draw(event){
if(lc==1){
var bb, x, y
bb = cnv.getBoundingClientRect()
x = (event.clientX-bb.left) * (cnv.width/bb.width)
y = (event.clientY-bb.top) * (cnv.height/bb.height)
if (prX!=-1){
ctx.beginPath()
ctx.moveTo(prX,prY)
ctx.lineTo(x,y)
ctx.lineWidth=10
ctx.closePath()
ctx.strokeStyle='rgb(0,0,0)'
ctx.stroke()
}
prX=x
prY=y
}
}
document.getElementById('recognize').addEventListener('click', function() {
var string = OCRAD(cnv)
alert(string)
});
</script>
Any help in fixing this is appreciated. Thank You.

There is some strange bug in your code or in library, here is another working example, that should help:
var c = document.getElementById('c'),
o = c.getContext('2d');
function reset_canvas() {
o.fillStyle = 'white'
o.fillRect(0, 0, c.width, c.height)
o.fillStyle = 'black'
}
var drag = false,
lastX, lastY;
c.onmousedown = function(e) {
drag = true;
lastX = 0;
lastY = 0;
e.preventDefault();
c.onmousemove(e)
}
c.onmouseup = function(e) {
drag = false;
e.preventDefault();
runOCR()
}
c.onmousemove = function(e) {
e.preventDefault()
var rect = c.getBoundingClientRect();
var r = 5;
function dot(x, y) {
o.beginPath()
o.moveTo(x + r, y)
o.arc(x, y, r, 0, Math.PI * 2)
o.fill()
}
if (drag) {
var x = e.clientX - rect.left,
y = e.clientY - rect.top;
if (lastX && lastY) {
var dx = x - lastX,
dy = y - lastY;
var d = Math.sqrt(dx * dx + dy * dy);
for (var i = 1; i < d; i += 2) {
dot(lastX + dx / d * i, lastY + dy / d * i)
}
}
dot(x, y)
lastX = x;
lastY = y;
}
}
document.body.ondragover = function() {
document.body.className = 'dragging';
return false
}
document.body.ondragend = function() {
document.body.className = '';
return false
}
document.body.onclick = function() {
document.body.className = '';
}
document.body.ondrop = function(e) {
e.preventDefault();
document.body.className = '';
picked_file(e.dataTransfer.files[0]);
return false;
}
function open_picker() {
var e = document.createEvent("MouseEvents");
e.initEvent('click', true, true);
document.getElementById('picker').dispatchEvent(e);
}
function runOCR(image_data, raw_feed) {
var response = OCRAD(c);
if ('innerText' in document.getElementById("text")) {
document.getElementById("text").innerText = response;
} else {
document.getElementById("text").textContent = response;
}
}
reset_canvas()
<script src="http://antimatter15.com/ocrad.js/ocrad.js"></script>
<div id="demo">
<canvas style="border:1px solid grey;" id='c' class="" width="300" height="150"></canvas>
<div class="output">
<div id="output">
<div id="text"></div>
<span id="timing"></span>
</div>
</div>
</div>

Related

Issue when dragging text on canvas if slightly scrolled down

When I scroll slightly down on my canvas, it does not allow me to drag my text at all. Examples (These are GIFs) -
https://gyazo.com/e60d2efd924ced758c2c6441391804db
GIF explained: So you saw the drag was working when I was on top of the page but when I scrolled slightly down. It completely stopped working. I added a few console.logs around, and what I know is the click event listener for the canvas is working but it isn't detected the text when I slightly scroll down on the page.
I based my drag code from: http://jsfiddle.net/m1erickson/9xAGa/ | What you can see is if you change the canvas size width: 667 and height: 800, and when you scroll slightly down, you will have the same issue I am having.
HTML Code:
<div id="middle_container">
<div class="center_container">
<canvas id="canvas" width="667px" height="800px"></canvas>
</div>
</div>
JavaScript Code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var BB=canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var mx;
var my;
var texts = [];
var images = [];
var dragF = -1;
var mode = "none";
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(const { text, x, y, width, height } of texts) {
ctx.fillText(text, x, y);
}
}
function addNewText(string_text) {
var y = texts.length * 20 + 20;
var text = {
text: string_text,
x: 20,
y: y
};
ctx.font = "32px verdana";
ctx.textBaseline = "top";
text.width = ctx.measureText(text.text).width;
text.height = 32;
texts.push(text);
draw();
}
function hitDrag(x,y,textIndex) {
var r=texts[textIndex];
return (x>r.x && x<r.x+r.width && y>r.y && y<r.y+r.height);
}
function myDrag(a,e) {
if (a == "down") {
e.preventDefault();
e.stopPropagation();
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
for(var i=0;i<texts.length;i++){
if(hitDrag(mx,my,i)){
console.log("found");
dragF = i;
}
}
}
}
addNewText("Hello World")
$("#canvas").mousedown(function(e) {
myDrag("down", e);
});
The problem is this line of code:
var BB=canvas.getBoundingClientRect();
which is only populated once at the start of your script. The .getBoundingClientRect() method returns the position of a HTML element relative to the viewport.
Well if you scroll the window, the viewport moves - as the canvas element - but the BB object still holds the position of your canvas at startup.
The fix is rather simple - you need to use the actual position of the canvas element by calling .getBoundingClientRect() again on mouse down and on mouse move.
I've prepared a little sample based on your code and the fiddle you've linked:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var $canvas = $("#canvas");
var BB = canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var mx;
var my;
var texts = [];
var images = [];
var dragF = -1;
var mode = "none";
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (const {
text,
x,
y,
width,
height
} of texts) {
ctx.fillText(text, x, y);
}
}
function addNewText(string_text) {
var y = texts.length * 20 + 20;
var text = {
text: string_text,
x: 20,
y: y
};
ctx.font = "32px verdana";
ctx.textBaseline = "top";
text.width = ctx.measureText(text.text).width;
text.height = 32;
texts.push(text);
draw();
}
function myDrag(a, e) {
if (a == "down") {
e.preventDefault();
e.stopPropagation();
let rect = canvas.getBoundingClientRect();
mx = parseInt(e.clientX - rect.left);
my = parseInt(e.clientY - rect.top);
for (var i = 0; i < texts.length; i++) {
if (hitDrag(mx, my, i)) {
// console.log("found");
dragF = i;
}
}
}
}
function hitDrag(x, y, textIndex) {
var r = texts[textIndex];
return (x > r.x && x < r.x + r.width && y > r.y && y < r.y + r.height);
}
function handleMouseMove(e) {
if (dragF < 0) {
return;
}
e.preventDefault();
let rect = canvas.getBoundingClientRect();
mouseX = parseInt(e.clientX - rect.left);
mouseY = parseInt(e.clientY - rect.top);
var dx = mouseX - mx;
var dy = mouseY - my;
mx = mouseX;
my = mouseY;
var text = texts[dragF];
text.x += dx;
text.y += dy;
draw();
}
function handleMouseUp(e) {
e.preventDefault();
dragF = -1;
}
addNewText("Hello World")
$("#canvas").mousedown(function(e) {
myDrag("down", e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
body {
background-color: ivory;
}
#canvas {
border: 1px solid red;
}
#theText {
width: 10em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="middle_container">
<div class="center_container">
<canvas id="canvas" width="667px" height="800px"></canvas>
</div>
</div>
<br><br><br><br><br><br><br><br><br><br>
<br><br><br><br><br><br><br><br><br><br>

Javascript subroutines don't run

So I am new to javascript and a beginner programmer. I know the initialization subroutine always go first. I don't get why the subroutines aren't running. And I was wondering if any variables in the initialization subroutine can be used in any other subroutines. I am trying to make a program using Bresenham Line Algorithm.
<html>
<head>
<body>
<canvas id="canvas" width="500" height="500" style="border: 1px solid black;" onclick="coordinates(event)">></canvas>
</body>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
intialization();
drawGrid();
mouseClick();
//Intialization--------------------------------
//Intialization--------------------------------
function intialization() {
var cnv = document.getElementById("canvas");
var Width = cnv.width;
var Height = cnv.height;
var ctx = cnv.getContext('2d');
var click_counter = 0; //switching between storing first and second point coordinates
p1x = 0; //stores user's click on canvas
p1y = 0; //stores user's click on canvas
p2x = 0; //stores user's click on canvas
p2y = 0; //stores user's click on canvas
}
//Intialization--------------------------------
//GRID---------------------------------
function drawGrid() {
var gridLines = {
Lines: {
space: 10,
// color: "'#xxxxxx'"
}
};
drawGridLines(cnv, gridLines.Lines);
return;
}
function drawGridLines(cnv, lineOptions) {
ctx.strokeStyle = lineOptions.color;
ctx.strokeWidth = 1;
ctx.beginPath();
var counter = null;
var i = null;
var x = null;
var y = null;
counter = Math.floor(Width / lineOptions.space);
for (i = 1; i <= counter; i++) {
x = (i * lineOptions.space);
ctx.moveTo(x, 0);
ctx.lineTo(x, Height);
ctx.stroke();
}
counter = Math.floor(Height / lineOptions.space);
for (i = 1; i <= counter; i++) {
y = (i * lineOptions.space);
ctx.moveTo(0, y);
ctx.lineTo(Width, y);
ctx.stroke();
}
ctx.closePath();
return;
}
//GRID---------------------------------
//MOUSE---------------------------------
function mouseClick {
if (click_counter = 0) {
function coordinates(event) {
var x1 = event.offsetX;
var y1 = event.offsetY;
p1x = x1;
p1y = y1;
console.log("x coords: " + p1x + ", y coords: " + p1y);
} else
function coordinates(event) {
var x1 = event.offsetX;
var y1 = event.offsetY;
p2x = x1;
p2y = y1;
console.log("x coords: " + p2x + ", y coords: " + p2y);
}
}
//MOUSE---------------------------------
//MOUSE---------------------------------
</script>
</head>
</html>
Your initialization and drawGrid functions are being called before the document is even loaded so this will fail. You should use the jquery method-
$(document).ready(function(){
//callyour functions here
})
Another issue you have is that you are trying to use variables which are out of scope. Like cnv for example. You should declare a object like canvas at the top of your js:
canvas = {}
and add all of the variables you want to share to this. for instance :
canvas.cnv = document.getElementById("canvas");
canvas.Width = canvas.cnv.width;
canvas.Height = canvas.cnv.height;
canvas.ctx = canvas.cnv.getContext('2d');
Here is a simple example of how to use the canvas:
<html>
<head>
<script src="index.js"></script>
<body>
<canvas id="canvas" width="500" height="500" style="border: 1px solid black;" onmousemove="mouseClick(event)">></canvas>
</body>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script>
canvas = {}
var isMouseDown = false;
document.addEventListener('mousedown', function(event) {
if ( event.which ) isMouseDown = true;
}, true);
document.addEventListener('mouseup', function(event) {
if ( event.which ) isMouseDown = false;
}, true);
$(document).ready(function(){
canvas.cnv = document.getElementById("canvas");
canvas.Width = canvas.cnv.width;
canvas.Height = canvas.cnv.height;
canvas.ctx = canvas.cnv.getContext('2d');
});
function mouseClick(e) {
console.log(isMouseDown)
if (isMouseDown){
var x1 = event.offsetX;
var y1 = event.offsetY;
canvas.ctx.lineTo(x1, y1);
canvas.ctx.stroke();
}
}
</script>
</head>
</html>

Two virtual joystick not coming

I am trying to make two joysticks on the single page with the help of code provided below but only one joystick appear.I am putting one - one joystick in different jumbotron , to differentiate. I tried even with different div id's but still it is not working. Also second jumbotron joystick is coming up in this example.
Can some help ??
Code :
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<link rel='stylesheet prefetch' href='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css'>
<script type="text/javascript" src="js/jquery-1.11.2.min.js"></script>
<script type="text/javascript" src="js/underscore-min.js"></script>
<script type="text/javascript" src="js/backbone-min.js"></script>
<script type="text/javascript" src="js/joystick_view.js"></script>
</head>
<body>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-3">Fluid jumbotron</h1>
<p class="lead">This is a modified jumbotron that occupies the entire horizontal space of its parent.</p>
<script type="text/html" id="joystick-view">
<canvas id="joystickCanvas" width="<%= squareSize %>" height="<%= squareSize %>" style="width: <%= squareSize %>px; height: <%= squareSize %>px;">
</canvas>
</script>
<div id="joystickContent">
</div>
<div>
firstx: <span id="xVal"></span><br/>
y: <span id="yVal"></span><br/>
</div>
<script type="text/javascript">
$(document).ready(function(){
var joystickView = new JoystickView(150, function(callbackView){
$("#joystickContent").append(callbackView.render().el);
setTimeout(function(){
callbackView.renderSprite();
}, 0);
});
joystickView.bind("verticalMove", function(y){
$("#yVal").html(y);
});
joystickView.bind("horizontalMove", function(x){
$("#xVal").html(x);
});
});
</script>
</div>
</div>
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-3">Fluid jumbotron</h1>
<p class="lead">This is a modified jumbotron that occupies the entire horizontal space of its parent.</p>
<script type="text/html" id="joystick-view">
<canvas id="joystickCanvas" width="<%= squareSize %>" height="<%= squareSize %>" style="width: <%= squareSize %>px; height: <%= squareSize %>px;">
</canvas>
</script>
<div id="joystickContent">
</div>
<div>
x: <span id="xVal"></span><br/>
y: <span id="yVal"></span><br/>
</div>
<script type="text/javascript">
$(document).ready(function(){
var joystickView1 = new JoystickView(150, function(callbackView){
$("#joystickContent").append(callbackView.render().el);
setTimeout(function(){
callbackView.renderSprite();
}, 0);
});
joystickView.bind("verticalMove", function(y){
$("#yVal").html(y);
});
joystickView.bind("horizontalMove", function(x){
$("#xVal").html(x);
});
});
</script>
</div>
</div>
</body>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src='http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js'></script>
</html>
plus this the javascript code working:
var INACTIVE = 0;
var ACTIVE = 1;
var SECONDS_INACTIVE = 0.5;
function loadSprite(src, callback) {
var sprite = new Image();
sprite.onload = callback;
sprite.src = src;
return sprite;
}
JoystickView = Backbone.View.extend({
events: {
"touchstart": "startControl",
"touchmove": "move",
"touchend": "endCotrol",
"mousedown": "startControl",
"mouseup": "endControl",
"mousemove": "move"
},
initialize: function(squareSize, finishedLoadCallback){
this.squareSize = squareSize;
this.template = _.template($("#joystick-view").html());
this.state = INACTIVE;
this.x = 0;
this.y = 0;
this.canvas = null;
this.context = null;
this.radius = (this.squareSize / 2) * 0.5;
this.finishedLoadCallback = finishedLoadCallback;
this.joyStickLoaded = false;
this.backgroundLoaded = false;
this.lastTouch = new Date().getTime();
self = this;
setTimeout(function(){
self._retractJoystickForInactivity();
}, 1000);
this.sprite = loadSprite("img/button.png", function(){
self.joyStickLoaded = true;
self._tryCallback();
});
this.background = loadSprite("img/canvas.png", function(){
self.backgroundLoaded = true;
self._tryCallback();
});
},
_retractJoystickForInactivity: function(){
var framesPerSec = 15;
var self = this;
setTimeout(function(){
var currentTime = new Date().getTime();
if(currentTime - self.lastTouch >= SECONDS_INACTIVE * 1000){
self._retractToMiddle();
self.renderSprite();
}
self._retractJoystickForInactivity();
}, parseInt(1000 / framesPerSec, 10));
},
_tryCallback: function(){
if(this.backgroundLoaded && this.joyStickLoaded){
var self = this;
this.finishedLoadCallback(self);
}
},
startControl: function(evt){
this.state = ACTIVE;
},
endControl: function(evt){
this.state = INACTIVE;
this.x = 0;
this.y = 0;
this.renderSprite();
},
move: function(evt){
if(this.state == INACTIVE){
return;
}
this.lastTouch = new Date().getTime();
var x, y;
if(evt.originalEvent && evt.originalEvent.touches){
evt.preventDefault();
var left = 0;
var fromTop = 0;
elem = $(this.canvas)[0];
while(elem) {
left = left + parseInt(elem.offsetLeft);
fromTop = fromTop + parseInt(elem.offsetTop);
elem = elem.offsetParent;
}
x = evt.originalEvent.touches[0].clientX - left;
y = evt.originalEvent.touches[0].clientY - fromTop;
} else {
x = evt.offsetX;
y = evt.offsetY;
}
this._mutateToCartesian(x, y);
this._triggerChange();
},
_triggerChange: function(){
var xPercent = this.x / this.radius;
var yPercent = this.y / this.radius;
if(Math.abs(xPercent) > 1.0){
xPercent /= Math.abs(xPercent);
}
if(Math.abs(yPercent) > 1.0){
yPercent /= Math.abs(yPercent);
}
this.trigger("horizontalMove", xPercent);
this.trigger("verticalMove", yPercent);
},
_mutateToCartesian: function(x, y){
x -= (this.squareSize) / 2;
y *= -1;
y += (this.squareSize) / 2;
if(isNaN(y)){
y = this.squareSize / 2;
}
this.x = x;
this.y = y;
if(this._valuesExceedRadius(this.x, this.y)){
this._traceNewValues();
}
this.renderSprite();
},
_retractToMiddle: function(){
var percentLoss = 0.1;
var toKeep = 1.0 - percentLoss;
var xSign = 1;
var ySign = 1;
if(this.x != 0){
xSign = this.x / Math.abs(this.x);
}
if(this.y != 0) {
ySign = this.y / Math.abs(this.y);
}
this.x = Math.floor(toKeep * Math.abs(this.x)) * xSign;
this.y = Math.floor(toKeep * Math.abs(this.y)) * ySign;
},
_traceNewValues: function(){
var slope = this.y / this.x;
var xIncr = 1;
if(this.x < 0){
xIncr = -1;
}
for(var x=0; x<this.squareSize / 2; x+=xIncr){
var y = x * slope;
if(this._valuesExceedRadius(x, y)){
break;
}
}
this.x = x;
this.y = y;
},
_cartesianToCanvas: function(x, y){
var newX = x + this.squareSize / 2;
var newY = y - (this.squareSize / 2);
newY = newY * -1;
return {
x: newX,
y: newY
}
},
_valuesExceedRadius: function(x, y){
if(x === 0){
return y > this.radius;
}
return Math.pow(x, 2) + Math.pow(y, 2) > Math.pow(this.radius, 2);
},
renderSprite: function(){
var originalWidth = 89;
var originalHeight = 89;
var spriteWidth = 50;
var spriteHeight = 50;
var pixelsLeft = 0; //ofset for sprite on img
var pixelsTop = 0; //offset for sprite on img
var coords = this._cartesianToCanvas(this.x, this.y);
if(this.context == null){
return;
}
// hack dunno why I need the 2x
this.context.clearRect(0, 0, this.squareSize * 2, this.squareSize);
var backImageSize = 300;
this.context.drawImage(this.background,
0,
0,
backImageSize,
backImageSize,
0,
0,
this.squareSize,
this.squareSize
)
this.context.drawImage(this.sprite,
pixelsLeft,
pixelsTop,
originalWidth,
originalHeight,
coords.x - spriteWidth / 2,
coords.y - spriteHeight / 2,
spriteWidth,
spriteHeight
);
},
render: function(){
var renderData = {
squareSize: this.squareSize
};
this.$el.html(this.template(renderData));
this.canvas = this.$('#joystickCanvas')[0];
this.context = this.canvas.getContext('2d');
this.renderSprite();
return this;
}
});
This is the image of whats happening

html5 Canvas display default area in canvas

I would like to display default my "Dedication Text" in the middle of my canvas.
I really can't determine the coordinates nor understand the codes...
Currently my Dedication Text displays here :
As you can see, it displays on the left top corner of the canvas.
Where I would like to automatically display is in the middle
Like this:
I have this code that I got from net:
function updateTotal() {
if (document.getElementById('design3').checked) {
var canvas2 = document.getElementById("displaycake_text");
context = canvas2.getContext("2d");
var $canvas2 = $("#displaycake_text");
var canvasOffset = $canvas2.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var scrollX = $canvas2.scrollLeft();
var scrollY = $canvas2.scrollTop();
var startX;
var startY;
var texts = []; // an array to hold text objects
var selectedText = -1;// this var will hold the index of the hit-selected text
function draw() { // clear the canvas & redraw all texts
context.clearRect(0, 0, canvas2.width, canvas2.height);
for (var i = 0; i < texts.length; i++) { var text = texts[i];
context.fillText(text.text, text.x, text.y); }
}
function textHittest(x, y, textIndex) { // test if x,y is inside the bounding box of texts[textIndex]
var text = texts[textIndex];
return (x >= text.x && x <= text.x + text.width && y >= text.y - text.height && y <= text.y);
}
function handleMouseDown(d) {
d.preventDefault();
startX = parseInt(d.clientX - offsetX);
startY = parseInt(d.clientY - offsetY);
for (var i = 0; i < texts.length; i++) {
if (textHittest(startX, startY, i)) {
selectedText = i; } }
}
function handleMouseUp(d) { // done dragging
d.preventDefault();
selectedText = -1; }
function handleMouseOut(d) { // also done dragging
d.preventDefault();
selectedText = -1; }
function handleMouseMove(d) {
if (selectedText < 0) { return; }
d.preventDefault();
mouseX = parseInt(d.clientX - offsetX);
mouseY = parseInt(d.clientY - offsetY);
var dx = mouseX - startX;
var dy = mouseY - startY;
startX = mouseX;
startY = mouseY;
var text = texts[selectedText];
text.x += dx;
text.y += dy;
draw(); }
$("#displaycake_text").mousedown(function (d) { handleMouseDown(d); }); // listen for mouse events
$("#displaycake_text").mousemove(function (d) { handleMouseMove(d); });
$("#displaycake_text").mouseup(function (d) { handleMouseUp(d); });
$("#displaycake_text").mouseout(function (d) { handleMouseOut(d); });
$("#text_dedi").click(function () {
var y = texts.length * 20 + 20;
var text = { text: $("#dedi_text").val(),
x: 20,
y: y
};
context.font = "30px Roboto";
text.width = context.measureText(text.text).width;
text.height = 16;
text.color = "#ffffff";
texts.push(text); // put this new text in the texts array
draw(); // redraw everything
});
//this is the code for CLEAR BUTTON
document.getElementById('clear').addEventListener('click', function() {
context.clearRect(0, 0, canvas2.width, canvas2.height);
texts = []; },
false);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="displaycake_text" height="300px" width="600px"> </canvas>
<!-- CLICK THE RADIO TO TRIGGER POST -->
<input type="radio" id="design3" name="design_3" onchange="updateTotal()" /> Dedication
<h2> <div class="disp_dedi off"> <input type="text" size="15" id="dedi_text" name="dedicationT" placeholder="Dedication">
<button id="text_dedi"> Post </button> <input type="button" value="Clear" id="clear" size="23" onchange="updateTotal()">
As you can see, I can drag it around... But I'm going to add some features that would decline the dragging part.
Can anyone help me point out which in the JS code that I could set the place of the text to be posted by default somewhere in the middle?
The source doesn't have enough comments for me to understand.
THANK YOU IN ADVANCE!!!
First you need to align the text that you are trying to draw on the canvas by using textAlign property of canvas.
Second you need to set the fillText's x, y coordinates according to half of the canvas width / height, so that you can place the text in the middle of the canvas. So, basically you have to add / change just 2 lines of code in your already existing snippet and that would be :
context.textAlign = 'center';
context.fillText(text.text, canvas2.width / 2, canvas2.height / 2);
and the good thing is it automatically removes the dragging part.
function updateTotal() {
if (document.getElementById('design3').checked) {
var canvas2 = document.getElementById("displaycake_text");
context = canvas2.getContext("2d");
var $canvas2 = $("#displaycake_text");
var canvasOffset = $canvas2.offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var scrollX = $canvas2.scrollLeft();
var scrollY = $canvas2.scrollTop();
var startX;
var startY;
var texts = []; // an array to hold text objects
var selectedText = -1; // this var will hold the index of the hit-selected text
function draw() { // clear the canvas & redraw all texts
context.clearRect(0, 0, canvas2.width, canvas2.height);
for (var i = 0; i < texts.length; i++) {
var text = texts[i];
context.textAlign = 'center';
context.fillText(text.text, canvas2.width / 2, canvas2.height / 2);
}
}
function textHittest(x, y, textIndex) { // test if x,y is inside the bounding box of texts[textIndex]
var text = texts[textIndex];
return (x >= text.x && x <= text.x + text.width && y >= text.y - text.height && y <= text.y);
}
function handleMouseDown(d) {
d.preventDefault();
startX = parseInt(d.clientX - offsetX);
startY = parseInt(d.clientY - offsetY);
for (var i = 0; i < texts.length; i++) {
if (textHittest(startX, startY, i)) {
selectedText = i;
}
}
}
function handleMouseUp(d) { // done dragging
d.preventDefault();
selectedText = -1;
}
function handleMouseOut(d) { // also done dragging
d.preventDefault();
selectedText = -1;
}
function handleMouseMove(d) {
if (selectedText < 0) {
return;
}
d.preventDefault();
mouseX = parseInt(d.clientX - offsetX);
mouseY = parseInt(d.clientY - offsetY);
var dx = mouseX - startX;
var dy = mouseY - startY;
startX = mouseX;
startY = mouseY;
var text = texts[selectedText];
text.x += dx;
text.y += dy;
draw();
}
$("#displaycake_text").mousedown(function(d) {
handleMouseDown(d);
}); // listen for mouse events
$("#displaycake_text").mousemove(function(d) {
handleMouseMove(d);
});
$("#displaycake_text").mouseup(function(d) {
handleMouseUp(d);
});
$("#displaycake_text").mouseout(function(d) {
handleMouseOut(d);
});
$("#text_dedi").click(function() {
var y = texts.length * 20 + 20;
var text = {
text: $("#dedi_text").val(),
x: 20,
y: y
};
context.font = "30px Roboto";
text.width = context.measureText(text.text).width;
text.height = 16;
text.color = "#ffffff";
texts.push(text); // put this new text in the texts array
draw(); // redraw everything
});
//this is the code for CLEAR BUTTON
document.getElementById('clear').addEventListener('click', function() {
context.clearRect(0, 0, canvas2.width, canvas2.height);
texts = [];
}, false);
}
}
#displaycake_text {
background-color: lightgrey;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="displaycake_text" height="300px" width="600px"> </canvas>
<!-- CLICK THE RADIO TO TRIGGER POST -->
<input type="radio" id="design3" name="design_3" onchange="updateTotal()" /> Dedication
<h2> <div class="disp_dedi off"> <input type="text" size="15" id="dedi_text" name="dedicationT" placeholder="Dedication">
<script src="https://code.jquery.com/jquery-3.1.0.js"></script>
<button id="text_dedi"> Post </button> <input type="button" value="Clear" id="clear" size="23" onchange="updateTotal()">

Optimize canvas drawing to make a continuous path

This is a script for filling canvas' grid squares with red color.
I'm looking for tips how to optimize my script to fill squares continuously, without chopping like here:
I tried to separate and merge some functions, but can't find a solution.
Here's the updated jsFiddle and my code:
HTML:
<canvas id="plan" width="501px" height="301px"></canvas>
JavaScript (updated):
var canvas = document.getElementById('plan');
var context = canvas.getContext('2d'),
wt = canvas.width,
ht = canvas.height;
var down = false;
var draw = function (e) {};
window.onload = grid();
var oldPos = {
mX: 0,
mY: 0
};
var dPos = {
mX: 0,
mY: 0
};
var curPos = {
mX: 0,
mY: 0
};
draw.to = function (X, Y) {
oldPos = getMousePos(canvas, e); //update position
var mposX = X,
mposY = Y;
mposX = mposX - mposX % 5;
mposY = mposY - mposY % 5;
context.fillStyle = "red";
context.fillRect(mposX + 0.5, mposY + 0.5, 5, 5);
};
draw.single = function (e) {
oldPos = getMousePos(canvas, e);
var mpos = getMousePos(canvas, e);
mpos.mX = mpos.mX - mpos.mX % 5;
mpos.mY = mpos.mY - mpos.mY % 5;
context.fillStyle = "red";
context.fillRect(mpos.mX + 0.5, mpos.mY + 0.5, 5, 5);
};
draw.move = function (e) {
if (down) {
curPos = getMousePos(canvas, e);
dPos.mX = Math.abs(curPos.mX - oldPos.mX); // distance between old & new (delta X)
dPos.mY = Math.abs(curPos.mY - oldPos.mY); // delta Y
if (dPos.mX >= 5 || dPos.mY >= 5) { // if the distance is bigger than 5px hz OR 5px vertical
lightIntermediateSquares(oldPos.mX, oldPos.mY, curPos.mX, curPos.mY); // ^ connect them
} else {
draw.single(e); // simple
}
}
};
draw.start = function (e) {
e.preventDefault();
down = true;
draw.single(e);
};
draw.stop = function (e) {
down = false;
};
function lightIntermediateSquares(startX, startY, endX, endY) {
for (var pct = 0; pct <= 1; pct += 0.03) {
var dx = endX - startX;
var dy = endY - startY;
var X = startX + dx * pct;
var Y = startY + dy * pct;
draw.to(X, Y); // is it okay?
}
}
function grid() {
context.strokeStyle = "#f0f0f0";
var h = 2.5,
p = 2.5;
context.strokeRect(0.5, 0.5, 5, 5);
for (i = 0; i < wt; i += p) {
p *= 2;
context.drawImage(canvas, p, 0);
}
for (i = 0; i < ht; i += h) {
h *= 2;
context.drawImage(canvas, 0, h);
}
}
function getMousePos(canvas, e) {
var rect = canvas.getBoundingClientRect();
return {
mX: e.clientX - rect.left - 1,
mY: e.clientY - rect.top - 1
};
}
canvas.addEventListener('mouseup', draw.stop, false);
canvas.addEventListener('mousedown', draw.start, false);
canvas.addEventListener('mousemove', draw.move, false);
canvas.addEventListener('mouseout', draw.stop, false);
Here's how to light the missing squares
Calculate a line between the previous mousemove and the current mousemove position.
Then walk that line using interpolation and color any grid squares that the line crosses.
// walk along a line from the last mousemove position
// to the current mousemove position.
// Then color any cells we pass over on our walk
for(var pct=0;pct<=1;pct+=0.06){
var dx = mouseX-lastX;
var dy = mouseY-lastY;
var X = parseInt(lastX + dx*pct);
var Y = parseInt(lastY + dy*pct);
if( !(X==lastForX && Y==lastForY) ){
draw.ColorCell(X,Y);
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/WvuHL/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var wt = canvas.width;
var ht = canvas.height;
var down = false;
var lastX=-20;
var lastY=-20;
var points=[];
var draw = function (e) {};
draw.started = false;
var count;
function interpolateLine(startX,startY,endX,endY){
var lastForX;
var lastForY;
//
for(var pct=0;pct<=1;pct+=0.06){
var dx = endX-startX;
var dy = endY-startY;
var X = startX + dx*pct;
var Y = startY + dy*pct;
if( !(X==lastForX && Y==lastForY) ){
draw.ColorCell(X,Y);
}
lastForX=X;
lastForY=Y;
}
}
draw.ColorCell=function(x,y){
var rw = x - 1;
var rh = y - 1;
rw = rw - rw % 5 + 0.5;
rh = rh - rh % 5 + 0.5;
context.fillStyle = "red";
context.fillRect( rw, rh, 5, 5);
};
draw.single = function (e) {
var mouseX=parseInt(e.clientX-offsetX);
var mouseY=parseInt(e.clientY-offsetY);
draw.ColorCell(mouseX,mouseY);
};
// mousemove
draw.move = function (e) {
if(!down){return;}
// get the current mouse position
var mouseX=parseInt(e.clientX-offsetX);
var mouseY=parseInt(e.clientY-offsetY);
// if we haven't moved off this XY, then don't bother processing further
if(mouseX==lastX && mouseY==lastY){return;}
// When running the for-loop below,
// many iterations will not find a new grid-cell
// so lastForX/lastForY will let us skip duplicate XY
var lastForX=lastX;
var lastForY=lastY;
// walk along a line from the last mousemove position
// to the current mousemove position.
// Then color any cells we pass over on our walk
for(var pct=0;pct<=1;pct+=0.06){
var dx = mouseX-lastX;
var dy = mouseY-lastY;
var X = parseInt(lastX + dx*pct);
var Y = parseInt(lastY + dy*pct);
if( !(X==lastForX && Y==lastForY) ){
draw.ColorCell(X,Y);
}
lastForX=X;
lastForY=Y;
}
// set this mouse position as starting position for next mousemove
lastX=mouseX;
lastY=mouseY;
};
// mousedown
draw.start = function (e) {
e.preventDefault();
lastX=parseInt(e.clientX-offsetX);
lastY=parseInt(e.clientY-offsetY);
down = true;
};
// mouseup
draw.stop = function (e) {
e.preventDefault();
down = false;
};
function grid() {
context.strokeStyle = "#f0f0f0";
var h = 2.5;
var p = 2.5;
context.strokeRect(0.5, 0.5, 5, 5);
for (i = 0; i < wt; i += p) {
p *= 2;
context.drawImage(canvas, p, 0);
}
for (i = 0; i < ht; i += h) {
h *= 2;
context.drawImage(canvas, 0, h);
}
}
canvas.addEventListener('mouseup', draw.stop, false);
canvas.addEventListener('mouseout', draw.stop, false);
canvas.addEventListener('mousedown', draw.start, false);
canvas.addEventListener('click', draw.single, false);
canvas.addEventListener('mousemove', draw.move, false);
grid();
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=501 height=301></canvas>
</body>
</html>

Categories

Resources