I have a canvas draw feature:
var sketcher = null;
var brush = null;
$(document).ready(function(e) {
brush = new Image();
brush.src = 'assets/brush2.png';
brush.onload = function(){
sketcher = new Sketcher( "sketch", brush );
}
});
That uses sketcher.js. This allows the user to stamp a pattern depending on what brush pattern is used.
I want to be able to save the users click positions to localstorage and recall them if possible.
Here is the positions I want to save on the image below you can see the orangey/yellow dots that a user has clicked. I want to be able to save them out and recall them.
Here's my dirty attempt, you'll have to clean it up a little bit:
http://jsfiddle.net/ACt6v/2/
var canvas = document.getElementById("the-canvas");
var ctx = canvas.getContext("2d");
var clicks = [];
var localStorageEnabled = typeof(Storage);
var loadLink = document.getElementById("load");
canvas.onmousedown = function(e) {
clicks.push({
x: e.clientX,
y: e.clientY
})
ctx.fillStyle="blue";
ctx.fillRect(e.clientX - 5, e.clientY - 5, 10, 10);
if( localStorageEnabled !=="undefined" ) {
localStorage["clicks"] = JSON.stringify(clicks);
}
}
loadLink.onmousedown = function(e) {
e.preventDefault();
console.log(localStorage["clicks"]); //view the console to see the clicks
var readClicks = JSON.parse(localStorage["clicks"]);
for (var i = 0 ; i < readClicks.length ; i++) {
ctx.fillStyle="red";
ctx.fillRect(readClicks[i].x - 5, readClicks[i].y - 5, 10, 10);
}
}
basically you save an array as a json string which contains all the coordinates of the points. This requires that the user clicks to create the dots. If you need to find the dots dynamically you will need another clean canvas.
Related
im trying to store the x and y coordinates after clicking on the canvas, i can set a marker position, i can show the x an y coordinates and a picture of a marker on that position, but now i want to store these coordinates so that when you reload the web browser, the marker position wil still be at his place where you first placed it.
full code down..
var context = (this.canvas.nativeElement as HTMLCanvasElement).getContext("2d")
//Map sprite
var mapSprite = new Image();
mapSprite.src = "http://antyradar.info/wp-content/uploads/commercial-tumilty-design-commercial-floor-plans.jpg";
var Marker = function () {
this.Sprite = new Image();
this.Sprite.src = "https://www.lasvegas-waterdelivery.com/wp-content/uploads/2016/07/5gal-cropped.png"
this.Width = 12;
this.Height = 20;
this.XPos = 0;
this.YPos = 0;
}
var Markers = new Array();
var rect = (this.canvas.nativeElement as HTMLCanvasElement).getBoundingClientRect();
var mouseClicked = function (mouse) {
// Get current mouse coords
var mouseXPos = (mouse.x - rect.left);
var mouseYPos = (mouse.y - rect.top);
console.log("x: " + mouseXPos);
console.log("y: " + mouseYPos)
console.log("Marker added");
// Move the marker when placed to a better location
var marker = new Marker();
marker.XPos = mouseXPos - (marker.Width * 37.7);
marker.YPos = mouseYPos - (marker.Height * 7);
Markers.push(marker);
for (var i = 0; i < Markers.length; i++) {
if(i > 1){
Markers.splice(marker);
}
}
sessionStorage.setItem('Marker', JSON.stringify(marker));
let store = sessionStorage.getItem('Marker');
console.log(store);
var remember = function(){
return store;
}
}
// Add mouse click event listener to canvas
/* (this.canvas.nativeElement as HTMLCanvasElement).addEventListener("mousedown", mouseClicked, false); */
var firstLoad = function () {
context.font = "15px Georgia";
context.textAlign = "center";
}
firstLoad();
var main = function () {
draw();
};
var width = (this.canvas.nativeElement as HTMLCanvasElement).width
var height = (this.canvas.nativeElement as HTMLCanvasElement).height
var draw = function () {
// Clear Canvas
context.fillStyle = "#000";
context.fillRect(0, 0, width, height);
// Draw map
// Sprite, X location, Y location, Image width, Image height
// You can leave the image height and width off, if you do it will draw the image at default size
context.drawImage(mapSprite, 0, 0, 700, 700);
// Draw markers
for (var i = 0; i < Markers.length; i++) {
var tempMarker = Markers[i];
// Draw marker
context.drawImage(tempMarker.Sprite, tempMarker.XPos, tempMarker.YPos, tempMarker.Width, tempMarker.Height);
}
};
setInterval(main, (1000 / 10)); // Refresh 60 times a second
}
You can use Window.sessionStorage to store your coordinates.
sessionStorage.setItem('Marker', JSON.stringify(marker));
If this is ionic 3 store the information in a Provider too keep it consistent from page to page/on refresh or use a service for ionic 4 (https://www.youtube.com/watch?v=MUvDM55PN9k - tutorial). To keep the information after closing and opening the app you could use the ionic file plugin https://ionicframework.com/docs/native/file or other such native storage.
I am using obelisk.js, which does not have a native way ( to my knowledge) of intersecting or raycasting for mouse picking, so I am trying to make my own methods, but I am not sure how to proceed.
Here's the code for a basic pen with a mouseover ( I want to detect when the mouse is on top of the cube):
Codepen sample
// Canvas & Scene Init:
var canvas = document.getElementById("canvas01");
var point = new obelisk.Point(210, 180);
var pixelView = new obelisk.PixelView(canvas, point);
// CUBE
var dimensionCube = new obelisk.CubeDimension(40, 40, 40);
var cubeColor = new obelisk.CubeColor();
var cube = new obelisk.Cube(dimensionCube, cubeColor);
var cubePos = new obelisk.Point3D(80, 80, 0);
pixelView.renderObject(cube, cubePos);
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
// Listener
canvas.addEventListener('mousemove', function(evt) {
var mousePos = getMousePos(canvas, evt);
var message = 'Mouse position: ' + mousePos.x + ',' + mousePos.y ;
console.log(message);
}, false);
Thanks.
So after a bit of scratching my head I managed to add easel.js which has a handy hit area function and mouse event handling , the catch is that one has to crate a bitmap from the obelisk.js canvas and use that for the hit area without re-rendering.
I still need to figure out an efficient way of adding more than one primitive, here's the code so far:
And of course if you have a better,different or more native way that would be great as well:
// Canvas & Scene Init:
var canvas = document.getElementById("canvas01");
var ctx = canvas.getContext("2d");
var point = new obelisk.Point(210, 180);
var pixelView = new obelisk.PixelView(canvas, point);
var dimensionCube = new obelisk.CubeDimension(40, 40, 40);
var cubeColor = new obelisk.CubeColor();
var cube = new obelisk.Cube(dimensionCube, cubeColor);
var cubePos = new obelisk.Point3D(80, 80, 0);
pixelView.renderObject(cube, cubePos);
// Easel.JS glob:
var stage = new createjs.Stage("canvas01");
init();
function init() {
stage.enableMouseOver(10);
// we get the rendered canvas
var dataUrl = canvas.toDataURL();
// make a bitmap
var bitmap = new createjs.Bitmap(dataUrl);
// You could also add a hit area here
stage.addChild(bitmap);
// and the event handling we are after:
bitmap.on("mouseover", handleInteraction);
bitmap.on("mouseout", handleInteraction);
}
function handleInteraction(event) {
if (event.type === "mouseover") {
dimensionCube = new obelisk.CubeDimension(40, 40, 120);
cube = new obelisk.Cube(dimensionCube, cubeColor);
pixelView.clear();
pixelView.renderObject(cube, cubePos);
console.log("over");
} else {
dimensionCube = new obelisk.CubeDimension(40, 40, 40);
cube = new obelisk.Cube(dimensionCube, cubeColor);
pixelView.clear();
pixelView.renderObject(cube, cubePos);
console.log("out");
}
}
Pen: Obelisk.js + Easel.js basic Mouseover
I've created a hexagonal grid using this JS library. The grid does get properly painted onto the Canvas. My issue is with trying to introduce events on mouse events. For instance, when I hover over a certain hexagon I want it's background color to change.
At the moment, only the last created hexagon will change on mouseover regardless of which hexagon the cursor is hovering over. How can I make the event listener update the specific hexagon over which the cursor exists?
If this is not possible due to painted objects becoming "rasterized" into the canvas, what alternate approach would be recommended?
The code is below:
<canvas id="stage"></canvas>
<script>
var element = document.getElementById("stage");
element.height = window.innerHeight;
element.width = window.innerWidth;
var stage = new createjs.Stage("stage");
stage.x = window.innerWidth/2;
stage.y = window.innerHeight/2;
stage.enableMouseOver();
var grid = new Grid();
grid.tileSize = 55;
var stageTransformer = new StageTransformer().initialize({ element: element, stage: stage });
stageTransformer.addEventListeners();
var tick = function (event) { stage.update(); };
var colorHexagon = function(hexagon, fill) {
hexagon.graphics
.beginFill(fill)
.beginStroke("rgba(50,50,50,1)")
.drawPolyStar(0, 0, grid.tileSize, 6, 0, 0);
};
var coordinates = grid.hexagon(0, 0, 3, true)
for (var i = 0; i < coordinates.length; i++) {
var q = coordinates[i].q,
r = coordinates[i].r,
center = grid.getCenterXY(q, r),
hexagon = new createjs.Shape();
hexagon.cursor = "pointer";
hexagon.addEventListener("mouseover", function() {
colorHexagon(hexagon, "rgba(50,150,0,1)")
});
hexagon.addEventListener("mouseout", function() {
colorHexagon(hexagon, "rgba(150,150,150,1)")
});
hexagon.q = q;
hexagon.r = r;
hexagon.x = center.x;
hexagon.y = center.y;
colorHexagon(hexagon, "rgba(150,150,150,1)");
stage.addChild(hexagon);
stage.update();
}
tick();
createjs.Ticker.setFPS(30);
createjs.Ticker.addEventListener("tick", tick);
</script>
This should work.
stage.addEventListener("mouseover", function(evt) {
colorHexagon(evt.target, "rgba(50,150,0,1)")
});
stage.addEventListener("mouseout", function(evt) {
colorHexagon(evt.target, "rgba(150,150,150,1)")
});
you can put them at the very bottom of your script. They don't have to be in a loop.
Bind your event handlers to the container of the hexagons instead of to each hexagon seperately and find the hexagon hovered over by using the coordinates of the mouse. And check the docs of the library, maybe they have a method for that included.
I am developing a canvas paint but I want to have an eraser there. So I use this lines to erase de content but when I click is clear the whole canvas.
//undo tool
var undo = new createjs.Bitmap(app.loader.getResult('undo'));
undo.name = 'undo';
undo.x = brush.x + 90;
undo.y = brush.y;
undo.addEventListener('click', this.undoHandler);
this.toolsContainer.addChild(undo);
//trash tool
var clear = new createjs.Bitmap(app.loader.getResult('clear'));
clear.name = 'clear';
clear.x = undo.x + 90;
clear.y = undo.y;
clear.addEventListener('click', this.clearHandler);
this.toolsContainer.addChild(clear);
undoHandler:function(){
if(tools.undoArray.length){
var lastItem = tools.undoArray.pop();
app.container.removeChild(lastItem);
var lastItem2 = tools.undoArray2.pop();
app.container.removeChild(lastItem2);
var lastItem3 = tools.undoArray3.pop();
app.container.removeChild(lastItem3);
app.stage.update();
}
},
clearHandler:function(){
app.container.removeAllChildren();
app.container.updateCache(clearhandler?"destination-out":"source-over");;
app.stage.update();
},
I trying to develop something like this erase
http://jsfiddle.net/lannymcnie/ZNYPD/
any idea?
well here http://jsfiddle.net/lannymcnie/ZNYPD/, the key is this:
wrapper.updateCache(erase?"destination-out":"source-over");
so...
var stage, wrapper,erase;
function init() {
var stage = new createjs.Stage("canvas");
createjs.Ticker.addEventListener("tick", stage);
// Add some text to draw on top of (also instructions)
stage.addChild(new createjs.Text("Click and Drag to Draw", "40px Arial", "#000000").set({x:200,y:200}));
// Set up the container. We use it to draw in, and also to get mouse events.
var wrapper = new createjs.Container();
wrapper.hitArea = new createjs.Shape(new createjs.Graphics().f("#000").dr(0,0,800,600));
wrapper.cache(0,0,800,600); // Cache it.
stage.addChild(wrapper);
// Create the shape to draw into
var drawing = new createjs.Shape();
wrapper.addChild(drawing);
var lastPoint = new createjs.Point();
wrapper.addEventListener("mousedown", function(event) {
// Store the position. We have to do this because we clear the graphics later.
lastPoint.x = event.stageX;
lastPoint.y = event.stageY;
erase = Math.floor(Math.random()*2);
wrapper.addEventListener("pressmove", function(event){
// Draw a round line from the last position to the current one.
drawing.graphics.ss(20, "round").s("#ff0000");
drawing.graphics.mt(lastPoint.x, lastPoint.y);
drawing.graphics.lt(event.stageX, event.stageY);
// Update the last position for next move.
lastPoint.x = event.stageX;
lastPoint.y = event.stageY;
// Draw onto the canvas, and then update the container cache.
wrapper.updateCache(erase==1?"destination-out":"source-over");
drawing.graphics.clear();
});
// Listen for mousemove
});
}
$(function(){
init();
})
the only difference is that the drawing is based on a random from 0 to 1 because in my example the erase gets these values from here erase = Math.floor(Math.random()*2);
I have achieved this by maintaining a array of mid points and using the globalCompositeOperation as destination-out and source-over to make a transparent eraser trail .
Following is the code that you need to use with a mouse move function
`var handleMouseMove = function (event) {
midPt = new createjs.Point(oldPt.x + stage.mouseX>>1, oldPt.y+stage.mouseY>>1);
if(curTool.type=="eraser"){
var tempcanvas = document.getElementById('drawcanvas');
var tempctx=tempcanvas.getContext("2d");
tempctx.beginPath();
tempctx.globalCompositeOperation = "destination-out";
tempctx.arc(midPt.x, midPt.y, 20, 0, Math.PI * 2, false);
tempctx.fill();
tempctx.closePath();
tempctx.globalCompositeOperation = "source-over";
drawingCanvas.graphics.clear();
// keep updating the array for points
arrMidPtx.push(midPt.x);
arrMidPty.push(midPt.y);
stage.addChild(drawingCanvas);
stage.update();
}
else if ( curTool.type=="pen"){
drawingCanvas.graphics.clear().setStrokeStyle(stroke, 'round', 'round').beginStroke(color).moveTo(midPt.x, midPt.y).curveTo(oldPt.x, oldPt.y, oldMidPt.x, oldMidPt.y);
arrMidPtx.push(midPt.x);
arrMidPty.push(midPt.y);
arrOldPtx.push(oldPt.x);
arrOldPty.push(oldPt.y);
arrOldMidPtx.push(oldMidPt.x);
arrOldMidPty.push(oldMidPt.y);
oldPt.x = stage.mouseX;
oldPt.y = stage.mouseY;
oldMidPt.x = midPt.x;
oldMidPt.y = midPt.y;
stage.addChild(drawingCanvas);
stage.update();
}
};`
I start on KineticJS (and on Canvas) and i'm creating a small game for learn...
Right now, I have just 2 layers :
First with a map composed by Kinetic.Image
Second with the last time who game as draw.
I want refresh display X time per second but after 20 or 30 times the game are really slow.. And it's the same when I flood event click ( who launch the draw function too)...
Moreover, i can see in the second layer : the old text are never clean, the new are added on top... :/
var stage;
var layers = {};
var CANEVAS_WIDTH = 800;
var CANEVAS_HEIGHT = 600;
var MAP_WIDTH = 10;
var MAP_HEIGHT = 10;
var MAPPING_WIDTH = 150;
var MAPPING_HEIGHT = 88;
var LEFT_X = 0;
var LEFT_Y = MAP_WIDTH*MAPPING_HEIGHT/2;
var TOP_X = MAP_WIDTH/2*MAPPING_WIDTH;
var TOP_Y = 0;
var VIEW_X = 0;
var VIEW_Y = 0;
var CURSOR_X = 6;
var CURSOR_Y = 0;
var images = {};
function loadImages(sources, callback)
{
var loadedImages = 0;
var numImages = 0;
// get num of sources
for (var src in sources)
numImages++;
for (var src in sources)
{
images[src] = new Image();
images[src].onload = function(){
if (++loadedImages >= numImages)
callback();
};
images[src].src = sources[src];
}
}
function getMouseInfo(mousePos)
{
var info = {screen_x : mousePos.x,
screen_y : mousePos.y,
mouse_x : mousePos.x+VIEW_X,
mouse_y : mousePos.y+VIEW_Y-LEFT_Y,
onMap : 0,
map_x : -1,
map_y : -1};
map_x = -(info.mouse_y - ((LEFT_Y * info.mouse_x) / TOP_X)) / MAPPING_HEIGHT;
map_y = -(-info.mouse_y - ((LEFT_Y * info.mouse_x) / TOP_X)) / MAPPING_HEIGHT;
if(map_x >= 0 && map_x < MAP_WIDTH && map_y >= 0 && map_y < MAP_HEIGHT)
{
info.map_y = parseInt(map_y);
info.map_x = parseInt(map_x);
info.onMap = 1;
}
return info;
}
function draw()
{
drawMap();
drawFPS();
stage.add(layers.mapLayer);
stage.add(layers.fpsLayer);
}
function drawFPS()
{
layers.fpsLayer.clear();
var fps = new Kinetic.Shape(function(){
var date = new Date();
var time = date.getTime();
var context = this.getContext();
context.beginPath();
context.font = "12pt Calibri";
context.fillStyle = "red";
context.fillText("FPS : "+time, 10, 20);
});
layers.fpsLayer.add(fps);
}
function drawMap()
{
var x=0,y=0;
layers.mapLayer.clear();
var s = new Kinetic.Shape(function(){
var context = this.getContext();
context.beginPath();
context.rect(0, 0, CANEVAS_WIDTH, CANEVAS_HEIGHT);
context.fillStyle = "#000";
context.fill();
context.closePath();
});
layers.mapLayer.add(s);
for(x=0; x<MAP_WIDTH; x++)
for(y=0;y<MAP_HEIGHT; y++)
{
var img = new Kinetic.Image({
image: ((x==CURSOR_X && y==CURSOR_Y)?images.testMapCursor:images.testMap)
});
img.x = x*MAPPING_WIDTH/2 + y*MAPPING_WIDTH/2 - VIEW_X;
img.y = (MAP_WIDTH-1)*MAPPING_HEIGHT/2 - x*MAPPING_HEIGHT/2 + y*MAPPING_HEIGHT/2 - VIEW_Y;
layers.mapLayer.add(img);
}
}
function changeCursorPosition(cursor_x, cursor_y)
{
CURSOR_X = cursor_x;
CURSOR_Y = cursor_y;
draw();
}
function initStage()
{
layers.mapLayer = new Kinetic.Layer();
layers.fpsLayer = new Kinetic.Layer();
draw();
}
/*
* INIT
*/
window.onload = function(){
stage = new Kinetic.Stage("container", <?=CANEVAS_WIDTH;?>, <?=CANEVAS_HEIGHT;?>);
stage.on("mousemove", function(){
var mouseInfo = getMouseInfo(stage.getMousePosition());
if(mouseInfo.onMap)
document.body.style.cursor = "pointer";
else
document.body.style.cursor = "default";
});
stage.on("mousedown", function(){
var mouseInfo = getMouseInfo(stage.getMousePosition());
if(mouseInfo.onMap)
changeCursorPosition(mouseInfo.map_x, mouseInfo.map_y);
});
var sources = {
testMap : "testMap.png",
testMapCursor : "testMapCursor.png"
};
loadImages(sources, initStage);
};
Sorry, my english are realy bad.
Thank all.
I know someone who is trying out KineticJS. I haven't used it myself, so I apologize that I cannot provide more specific help.
Unfortunately, it is very difficult to get good performance with canvas, and it depends greatly on the browser. Last I checked, Opera 12 and IE 9 performed significantly faster than other browsers, since their 2D rendering is 3D accelerated (using OpenGL and Direct3D, respectively)
I am not sure if this applies to KineticJS, but one technique you can use to improve performance with canvas is to use multiple canvas elements, and transform their positions rather than blitting on a single surface.
I've been pretty happy with the results I've gotten using Jeash, which is wired into NME's command-line tools. The development is similar to working with Flash, but it will create an HTML5 Canvas application using your code. The same application will also be able to publish to Windows, Mac, Linux, iOS, Android, webOS and Flash, as either native C++ and OpenGL, or as SWF bytecode. This gives you a lot of options for providing the best experience for each user.
http://www.haxenme.org