I'm currently working on an iOS app which uses HTML 5 and JavaScript for drawing Graphs.
I just did a sample App.
My Code:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
var a = 0;
var b = 0;
function init()
{
var can = document.getElementById('can');
can.addEventListener("click",click, false);
}
function click(event)
{
var can = document.getElementById('can');
var c = can.getContext('2d');
var parentPosition = getPosition(event.currentTarget);
c.lineWidth = 1;
c.strokeStyle = '#FFFFFF';
c.beginPath();
c.moveTo(a, b);
a = event.clientX - parentPosition.x;
b = event.clientY - parentPosition.y;
c.lineTo(a, b);
c.stroke();
}
function getPosition(element)
{
var xPosition = 0;
var yPosition = 0;
while (element)
{
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
</script>
</head>
<body oncopy='copy();' onpaste='paste();'onload ='init();'>
<canvas id="can" style="height:300px;width:300px;background-color:black;">Oops!</canvas>
</body>
</html>
My Issue:
When a user Taps on the screen, I'm drawing a line to that particular point from previous point.
But in my case when I tap on the screen the line is drawn to some other point. Say if I tapped on point (100,100) the line will be drawn to (100, some arbitrary value). Always the Y position is wrong.
What I did:
Tested it on simulator
Tested it on device
Tested it on Firefox
Tested it on Chrome
All results are same. I couldn't find the issue. I alerted the clicked x and y co-ordinate. It's coming correctly. Only problem is with the draw functionality.
Screenshots:
As you can see the X-coordinate is correct. But Y-coordinate is always coming wrong.
Please help me, Thanks in advance.
Can you please make these changes.
In html line#47,
<canvas id="can" height=300 width=300 style="background-color:red;">Oops!</canvas>
In script line#23,
c.beginPath();
c.moveTo(a, b);
a = event.clientX - parentPosition.x;
b = event.clientY - parentPosition.y;
console.log('a:'+a+'--b:'+b);
c.lineTo(a, b);
c.stroke();
TO CLEAR
This is the code that you have to change to have a reusable code:
c.moveTo(a/(can.clientWidth/can.width), b/(can.clientHeight/can.height));
a = event.clientX - parentPosition.x;
b = event.clientY - parentPosition.y;
console.log('a:'+a+'--b:'+b);
c.lineTo(a/(can.clientWidth/can.width), b/(can.clientHeight/can.height));
If you don't use this, the code below works only for 300x300 canvas size.
LAST EDIT:
By analyzing the 2d context (var c = can.getContext('2d');console.log(c);) you can easily understand this error: there is a relation (not explicit) from the canvas and it's 2d context.
As you can see from the image:
the height and the width of the canvas(this is 500*500) are differents from its offset,scroll and client size. So, before to draw, you need to calculate the ratio: 500/150 will be the height coefficient and 500/300 the width one, so a will be multiplied by 1.66667 and b will be multiplied by 3.33333.
Same for the old example (canvas 300*300) the coefficent are 300/300=1 (a:width) 300/150=2 (b:height)
OLD REPLY:
But now, you have to guess why..cause actually I have no time
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script type="text/javascript">
var a = 0;
var b = 0;
function init()
{
var can = document.getElementById('can');
can.addEventListener("click",click, false);
}
function click(event)
{
var can = document.getElementById('can');
var c = can.getContext('2d');
var parentPosition = getPosition(event.currentTarget);
console.log(parentPosition);
console.log(event);
c.lineWidth = 1;
c.strokeStyle = '#FFFFFF';
c.beginPath();
c.moveTo(a, b/2);
a = event.clientX - parentPosition.x;
b = event.clientY - parentPosition.y;
console.log('a:'+a+'--b:'+b);
c.lineTo(a, b/2);
c.stroke();
}
function getPosition(element)
{
var xPosition = 0;
var yPosition = 0;
while (element)
{
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
</script>
</head>
<body oncopy='copy();' onpaste='paste();'onload ='init();'>
<canvas id="can" style="height:300px;width:300px;background-color:black;">Oops!</canvas>
<br>
pagex<input type="text" id="ics">pagey<input type="text" id="ips"><br>
screenx<input type="text" id="ics2">screeny<input type="text" id="ips2">
<script>
$("#can").mousemove(function(event) {
var msg = "Handler for .mousemove() called at ";
document.getElementById('ics').value= event.pageX
document.getElementById('ips').value= event.pageY;
document.getElementById('ics2').value= event.screenX;
document.getElementById('ips2').value= event.screenY;
});
</script>
</body>
</html>
Related
I am tring to implement this example http://jsfiddle.net/vY2B4/1/ in my mobile applicaion
I am using onsen with angularjs to build the mobile application
what I need is to display the pdf file in onsen tab
<ons-page id="PDFPlam.html" ng-controller="pdfPlanCtrl">
<button class="button button-block button-positive"></button>
<canvas id="canvas" width="800" height="600">
Your browser does not support the canvas element.
</canvas>
</ons-page>
and this is my controller
angular.module('myApp').controller('pdfPlanCtrl',['$scope', function($scope) {
$scope.canvas ;
$scope.context
addEventListener('load', load, false);
function load(){
alert('loaded');
$scope.canvas = document.getElementById("canvas");
console.log('canvas is '+ $scope.canvas);
$scope.context = document.getElementById('canvas').getContext('2d');
var mountain = new Image();
mountain.onload = function() {
console.log('init pdf');
$scope.context.drawImage(this, 0, 0);
initPointCollection();
}
mountain.src = 'file:///storage/emulated/0/Android/data/com.example.helloworld/files/249_139.jpg';
}
var points = [];
// Determine where the user clicked, I believe I pulled this from elsewhere on StackOverflow a while ago.
function getCursorPosition(e) {
var mx, my;
if (e.pageX || e.pageY) {
mx = e.pageX;
my = e.pageY;
}
else {
mx = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
my = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
}
mx -= canvas.offsetLeft;
my -= canvas.offsetTop;
return {x: mx, y: my};
}
// Once we have at least two points, draw a line between them.
function drawPath() {
context.beginPath();
for (var i = 0; i < points.length - 1; i++) {
context.moveTo(points[i]['x'], points[i]['y']);
context.lineTo(points[i+1]['x'], points[i+1]['y']);
context.stroke();
}
context.closePath();
}
// Listen for clicks, and redraw the map when they occur.
function initPointCollection() {
canvas.onclick = function(e) {
var point = getCursorPosition(e);
points.push(point);
if (points.length > 1) {
drawPath();
}
}
}
$scope.initPDFPlan = function() {
// Load up your image. Don't attempt to draw it until we know it's been loaded.
}
}]);
the problem that the Ioad function is not called so it is not work
I used interact.js library to write this piece of code which works absolutely fine standalone on chrome, firefox and w3schools "Try it Yourself" (doesn't work on Edge and IE for some reason). The problem is that when I call a template.phtml with this code inside from the layout.xml, the magento renders it only once, thus the user is not allowed to resize the cubes.
<!-- CSS -->
<style type="text/css">
svg {
width: 100%;
height: 300px;
background-color: #CDC9C9;
-ms-touch-action: none;
touch-action: none;
}
.edit-rectangle {
fill: black;
stroke: #fff;
}
body { margin: 0; }
</style>
<!-- Content -->
<br>
<svg>
</svg>
<br>
<button onclick="location.href = 'square';" id="previousbutton">Go back</button>
<button onclick="location.href = 'squaresection';" style="float:right" id="nextButton">Proceed to next step</button>
<br>
<br>
<script type="text/javascript" src="interact.js">
</script>
<!-- JavaScript -->
<script type="text/javascript">
var svgCanvas = document.querySelector('svg'),
svgNS = 'http://www.w3.org/2000/svg',
rectangles = [];
labels = [];
rectNumb = 5;
function Rectangle (x, y, w, h, svgCanvas) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.stroke = 0;
this.el = document.createElementNS(svgNS, 'rect');
this.el.setAttribute('data-index', rectangles.length);
this.el.setAttribute('class', 'edit-rectangle');
rectangles.push(this);
this.draw();
svgCanvas.appendChild(this.el);
}
function Label (x, y, text, svgCanvas){
this.x = x;
this.y = y;
this.text = text;
this.el = document.createElementNS(svgNS, 'text');
labels.push(this);
this.draw();
svgCanvas.appendChild(this.el);
}
Label.prototype.draw = function () {
this.el.setAttribute('x', this.x);
this.el.setAttribute('y', this.y);
this.el.setAttribute('font-family', "Verdana");
this.el.setAttribute('font-size', 14);
this.el.setAttribute('fill', "black");
this.el.innerHTML = this.text;
}
Rectangle.prototype.draw = function () {
this.el.setAttribute('x', this.x + this.stroke / 2);
this.el.setAttribute('y', this.y + this.stroke / 2);
this.el.setAttribute('width' , this.w - this.stroke);
this.el.setAttribute('height', this.h - this.stroke);
this.el.setAttribute('stroke-width', this.stroke);
}
interact('.edit-rectangle')
// change how interact gets the
// dimensions of '.edit-rectangle' elements
.rectChecker(function (element) {
// find the Rectangle object that the element belongs to
var rectangle = rectangles[element.getAttribute('data-index')];
// return a suitable object for interact.js
return {
left : rectangle.x,
top : rectangle.y,
right : rectangle.x + rectangle.w,
bottom: rectangle.y + rectangle.h
};
})
/*
.draggable({
max: Infinity,
onmove: function (event) {
var rectangle = rectangles[event.target.getAttribute('data-index')];
rectangle.x += event.dx;
rectangle.y += event.dy;
rectangle.draw();
}
})
*/
.resizable({
onstart: function (event) {},
onmove : function (event) {
if (event.target.getAttribute('data-index') > 0)
{
// Main Rect
var rectangle = rectangles[event.target.getAttribute('data-index')];
var rectangle2 = rectangles[event.target.getAttribute('data-index') - 1];
if (rectangle.w - event.dx > 10 && rectangle2.w + event.dx > 10){
rectangle.x += event.dx;
rectangle.w = rectangle.w - event.dx;
rectangle2.w = rectangle2.w + event.dx;
}
rectangle.draw();
rectangle2.draw();
var label = labels[event.target.getAttribute('data-index')];
var label2 = labels[event.target.getAttribute('data-index') - 1];
label.text = rectangle.w + " mm";
label2.text = rectangle2.w + " mm";
label.x = rectangle.x + rectangle.w / 4;
label2.x = rectangle2.x + rectangle2.w / 4;
label.draw();
label2.draw();
}
},
onend : function (event) {},
edges: {
top : false, // Disable resizing from top edge.
left : true,
bottom: false,
right : false // Enable resizing on right edge
},
inertia: false,
// Width and height can be adjusted independently. When `true`, width and
// height are adjusted at a 1:1 ratio.
square: false,
// Width and height can be adjusted independently. When `true`, width and
// height maintain the aspect ratio they had when resizing started.
preserveAspectRatio: false,
// a value of 'none' will limit the resize rect to a minimum of 0x0
// 'negate' will allow the rect to have negative width/height
// 'reposition' will keep the width/height positive by swapping
// the top and bottom edges and/or swapping the left and right edges
invert: 'reposition',
// limit multiple resizes.
// See the explanation in the #Interactable.draggable example
max: Infinity,
maxPerElement: 3,
});
interact.maxInteractions(Infinity);
var positionX = 50,
positionY = 80,
width = 80,
height = 80;
for (var i = 0; i < rectNumb; i++) {
positionX = 50 + 82 * i;
new Rectangle(positionX, positionY, width, height, svgCanvas);
}
for (var i = 0; i < rectNumb; i++) {
positionX = 50 + 82 * i;
new Label(positionX + width/4, positionY + height + 20, width +" mm", svgCanvas);
}
</script>
Any suggestions of what I could do to implement this code into magento would be much appreciated.
Magento did not render the code only once. The problem was that canvas event listener always assumed that pointer coordinates were wrong. Since canvas is the first element of the page(because it is the first element in that .phtml file), event listener assumed it will be displayed at the top, but that was not the case because of the way magento page rendering works.
This issue was resolved simply by measuring the height of content above canvas and just mathematically subtracting that from pointers position before passing it to event listener.
The problem with this solution is that it works only for single page or with multiple pages that have the same height of content above canvas(=>same design). If anyone knows a way in which person would not need to "recalculate" the height for every single page that has different design, sharing knowledge would be much appreciated.
well right now im trying to learn how to use the canvas tag on html, and im having trouble handling mouse events when i apply css to the document.
the issue starts when i move the div containing the canvas and center it on the page, the first poing of the canvas wouldnt be 0 because its centered and for some reason 0,0 would be the beginning of the screen and not the beginning of the canvas, which i found weird because im adding the event listener to the canvas directly.
here is the code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>test</title>
<style type="text/css">
body {
font: 100%/1.4 Verdana, Arial, Helvetica, sans-serif;
background: #42413C;
margin: 0;
padding: 0;
color: #000;
}
#divId {
width: 800px;
height: 600px;
text-align:center;
margin: 20px auto;
background-color:#0099FF;
}
</style>
<script>
window.onload = function () {
var canvas = document.getElementById('canvasId');
var c = canvas.getContext('2d');
alert("lol");
canvas.addEventListener('mousedown', hmd, false);
function hmd(e) {
alert ("x: " + e.clientX + " y: " + e.clientY);
}
}
</script>
</head>
<body>
<div id="divId">
<canvas height="300" width="800" id="canvasId" />
</div>
</body>
</html>
so i read somewhere that the issue was caused by the div, but when i tried to give css directly to the canvas tag it didnt work, so basically what i need to do, is to get that canvas centered or placed anywhere on the screen, but having its first pixel as 0,0.
adding a solution would be hard because its centering automatically, so i would need to know the user resolution to be able to calculate the offset so what im looking for is a way to do it simply with css or something.
To get the coordinates relatively to the canvas, do this:
function hmd(e) {
var rx = e.pageX, ry = e.pageY;
rx -= canvas.offsetLeft;
ry -= canvas.offsetTop;
alert ("x: " + rx + " y: " + ry);
}
This assumes your canvas variable definition is global.
Edit: another method:
function hmd(e) {
var rx, ry;
if(e.offsetX) {
rx = e.offsetX;
ry = e.offsetY;
}
else if(e.layerX) {
rx = e.layerX;
ry = e.layerY;
}
}
Here's what I've been using for my latest experimentation. It works with damn near everything: Borders, paddings, position:fixed elements offsetting the HTML element, etc. It also works on all touch devices and even if the browser is zoomed.
http://jsfiddle.net/simonsarris/te8GQ/5/
var stylePaddingLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingLeft'], 10) || 0;
var stylePaddingTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['paddingTop'], 10) || 0;
var styleBorderLeft = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderLeftWidth'], 10) || 0;
var styleBorderTop = parseInt(document.defaultView.getComputedStyle(can, undefined)['borderTopWidth'], 10) || 0;
var html = document.body.parentNode;
var htmlTop = html.offsetTop;
var htmlLeft = html.offsetLeft;
function getMouse(e) {
var element = can,
offsetX = 0,
offsetY = 0,
mx, my;
// Compute the total offset
if (element.offsetParent !== undefined) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
// Add padding and border style widths to offset
// Also add the <html> offsets in case there's a position:fixed bar
offsetX += stylePaddingLeft + styleBorderLeft + htmlLeft;
offsetY += stylePaddingTop + styleBorderTop + htmlTop;
mx = e.pageX - offsetX;
my = e.pageY - offsetY;
// We return a simple javascript object (a hash) with x and y defined
return {
x: mx,
y: my
};
}
Currently I'm creating a sheet of graph paper with the canvas object in HTML5. I'm able to create the canvas as well as fill in the selected areas with a color by finding the x/y position. Unfortunately I'm having some troubles using the jQuery mousemove method to display a pop-up of the information selected for the square.
Here's my code:
Canvas Creation/Layout:<br>
<script type="text/javascript">
var canvas;
var context;
var color;
var state;
var formElement;
var number = 0;
function showGrid()
{
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
context.lineWidth=0.5;
context.strokeStyle='#999999';
lineSpacing=10;
var xPos = 0;
var yPos = 0;
var numHorizontalLines = parseInt(canvas.height/lineSpacing);
var numVerticalLines = parseInt(canvas.width/lineSpacing);
state = new Array(numHorizontalLines);
for (var y = 0; y < numHorizontalLines; ++y)
{
state[y] = new Array(numVerticalLines);
}
for(var i=1; i<=numHorizontalLines;i++)
{
yPos=i*lineSpacing;
context.moveTo(0,yPos);
context.lineTo(canvas.width,yPos);
context.stroke;
}
for(var i=1; i<=numVerticalLines; i++)
{
xPos=i*lineSpacing;
context.moveTo(xPos,0);
context.lineTo(xPos,canvas.height);
context.stroke();
}
}
function fill(s, gx, gy)
{
context.fillStyle = s;
context.fillRect(gx * lineSpacing, gy * lineSpacing, lineSpacing, lineSpacing);
if(s != null)
{
}
}
function getPosition(e)
{
var x = new Number();
var y = new Number();
var canvas = document.getElementById("canvas");
if (e.pageX || e.pageY)
{
x = e.pageX;
y = e.pageY;
}
else
{
x = e.clientX + document.body.scrollLeft +
document.documentElement.scrollLeft;
y = e.clientY + document.body.scrollTop +
document.documentElement.scrollTop;
}
x -= canvas.offsetLeft;
y -= canvas.offsetTop;
var gx = Math.floor((x / lineSpacing));
var gy = Math.floor((y / lineSpacing));
state[gy][gx] = true;
fill(color, gx, gy);
addNumber();
}
HTML:
<div class="graphpaper" id="graphpaper" onclick="getPosition(event)" style="width:956px; height:1186px;">
<img src="images/PosterBorder_Top.png" align="right"/>
<img src="images/posterBorder_left.png" align="left" valign="top"/>
<canvas id ="canvas" width = "920" height = "1160" align="left">
</canvas>
</div>
<!-- HIDDEN / POP-UP DIV -->
<div id="pop-up">
<h3>Pop-up div Successfully Displayed</h3>
<p>
This div only appears when the trigger link is hovered over.
Otherwise it is hidden from view.
</p>
</div>
jQuery for Pop-Up display:
$('#canvas').mousemove(function(event){
console.log("Here I am!");
$('div#pop-up').show().appendTo('body');
});
Any suggestions? I'm obviously missing something but from what I've done this should work I believe.
I'm trying to simulate the Matrix code rain with the canvas element and javascript. I am able to make one element drop at a time but not multiple. How do I drop multiple matrix rain drops. Here is my code:
<html>
<head>
<title>Matrix Code Rain</title>
<style>
*{margin:0; padding:0; }
body{background:black;}
</style>
</head>
<body>
<canvas id="c"></canvas>
<script type="text/javascript">
var canvas = document.getElementById("c");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
canvas.style.background = "black";
var c = canvas.getContext("2d");
var code = ["<html>","<p>","<b>","<strong>","<head>","<body>","<a>","<i>","<div>","<form>","<ol>","<li>","<ul>","<pre>","<nav>","<footer>","<header>","<article>","<section>","<em>","<style>","<title>","<meta>","<br>","<table>"];
var rain = [ ];
var max = 10;
for(var i = 0; i < max; i++){
var drop = {};
drop.code = Math.round(Math.random() * code.length);
drop.x = Math.random() * canvas.width;
drop.y = 0;
drop.size = Math.random() * 40;
drop.speed = drop.size/4;
rain.push(drop);
}
var y = 0;
c.fillStyle="lime";
setTimeout(function(){
c.clearRect(0,0,canvas.width,canvas.height);
for(var i = 0; i < max; i++){
var drop = rain[i];
c.font = drop.size+"pt arial";
c.fillText(drop.code,drop.x,drop.y);
drop.y += drop.speed;
if(drop.y > canvas.height + drop.size)
drop.y = 0;
}
},1000/60);
</script>
</body>
</html>
Make a bunch of independent objects that all get their own word and position and speed.
Then print them all and advance them by their speed.
Here's a clean example for you:
http://jsfiddle.net/U5eFJ/
The important code:
var code = ["<html>", "<p>", "<b>", "<strong>", "<head>", "<body>", "<a>", "<i>", "<div>", "<form>", "<ol>", "<li>", "<ul>", "<pre>", "<nav>", "<footer>", "<header>", "<article>", "<section>", "<em>", "<style>", "<title>", "<meta>", "<br>", "<table>"];
// make 90 things to fall with a random code element and random starting location
var things = [];
var THINGCOUNT = 90;
for (var i = 0; i < THINGCOUNT; i++) {
var a = {};
//randomly pick one tag
a.code = code[Math.round(Math.random() * code.length)];
a.x = Math.random()*500; //random X
a.y = Math.random()*500 -500; // random Y that is above the screen
a.speed = Math.random()*10;
things.push(a);
}
setInterval(function() {
ctx.clearRect(0,0,500,500);
for (var i = 0; i < THINGCOUNT; i++) {
var a = things[i];
ctx.fillText(a.code, a.x, a.y);
a.y += a.speed; // fall downwards by the speed amount
if (a.y > 600) a.y = -50; // if off the screen at bottom put back to top
}
}, 90);
If you are running a windows computer you can make the java script open a .bat file that just says this.
`#echo off
mode 1000
#color a
:A
echo %random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%%random%
goto A'
This may not be what you want but I hope it helps =)
`