I have successfully created a button which rotates an image either clockwise or C-Clockwise. However, this button can only be used once. i.e. if i press CW i cannot then use CCW to revert the image back.
Any ideas?
$rw = $('#rotate_right');
$rw.on('click', function(event) { event.preventDefault ? event.preventDefault() : event.returnValue = false;
darthVaderImg.offsetX(img_width / 2);
darthVaderImg.offsetY(img_height / 2);
// when we are setting {x,y} properties we are setting position of top left corner of darthVaderImg.
// but after applying offset when we are setting {x,y}
// properties we are setting position of central point of darthVaderImg.
// so we also need to move the image to see previous result
darthVaderImg.x(darthVaderImg.x() + img_width / 2);
darthVaderImg.y(darthVaderImg.y() + img_height / 2);
darthVaderImg.rotation(90);
stage.batchDraw();
export_changes();
});
$rl = $('#rotate_left');
$rl.on('click', function(event) {
event.preventDefault ? event.preventDefault() : event.returnValue = false;
//darthVaderImg.rotate(90);
darthVaderImg.offsetX(img_width / 2);
darthVaderImg.offsetY(img_height / 2);
// when we are setting {x,y} properties we are setting position of top left corner of darthVaderImg.
// but after applying offset when we are setting {x,y}
// properties we are setting position of central point of darthVaderImg.
// so we also need to move the image to see previous result
darthVaderImg.x(darthVaderImg.x() + img_width / 2);
darthVaderImg.y(darthVaderImg.y() + img_height / 2);
darthVaderImg.rotation(-90);
stage.batchDraw();
export_changes();
});`
rotation method will set the current angle of a shape. if you need to rotate more you can use this:
var oldRotation = node.rotation();
node.rotation(oldRotation + 90);
or just:
node.rotate(90);
Based on #lavrton's answer, here is a working snippet. I guess you need to pay attention to the rotation point - it was easy for me as I used a wedge. See the brief code in the button click events for illustration on what to do.
// add a stage
var s = new Konva.Stage({
container: 'container',
width: 800,
height: 200
});
// add a layer
var l = new Konva.Layer();
s.add(l);
// Add a green rect to the LAYER just to show boundary of the stage.
var green = new Konva.Rect({stroke: 'lime', width: 799, height: 199, x: 0, y: 0});
l.add(green);
// add a circle to contain the wedge
var circle = new Konva.Circle({
x: s.getWidth() / 2,
y: s.getHeight() / 2,
radius: 70,
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
l.add(circle);
// add the wedge - used as our rotation example
var w = new Konva.Wedge({
x: s.getWidth() / 2,
y: s.getHeight() / 2,
radius: 70,
angle: 60,
fill: 'lime',
stroke: 'black',
strokeWidth: 4,
rotation: -120
});
l.add(w);
l.draw(); // redraw the layer it all sits on.
// wire up the buttons
var oldAngle = 0;
$( document ).ready(function() {
$('#plus90').on('click', function(e){
oldAngle = w.rotation();
w.rotate(90);
$('#info').html('Rotation is ' + oldAngle + ' + 90 = ' + w.rotation())
l.draw();
})
$('#minus90').on('click', function(e){
oldAngle = w.rotation();
w.rotate(-90);
$('#info').html('Rotation is ' + oldAngle + ' - 90 = ' + w.rotation())
l.draw();
})
$('#info').html('Initial rotation = ' + w.rotation())
});
#container {
border: 1px solid #ccc;
}
#info {
height: 20px;
border-bottom: 1px solid #ccc;
}
#hint {
font-style: italic;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.3/konva.min.js"></script>
<body>
<div id='hint'>Hint: green is stage, red circle is static, lime wedge rotates.Click the buttons!<br/>
Note the initial rotation set on the creation of the wedge.
</div>
<div id='info'>Info:</div>
<div id='ctrls'>
<button id='minus90'>Rotate -90 degrees</button>
<button id='plus90'>Rotate +90 degrees</button>
</div>
<div id="container"></div>
</body>
Related
I am using Konva library for drawing a canvas and dragging images onto it
My question is how can I select a part of canvas and fill color to the selected portion using Konva
1) users select a portion by dragging mouse
2) fill color what he wants to the selected portion
The only way to have part of the canvas filled is to use a shape.
This snippet should get you going.
To select the fill color you will need to open some kind of custom color selection process in the mouseup event.
// Set up the canvas and shapes
var s1 = new Konva.Stage({container: 'container1', width: 300, height: 200});
var layer1 = new Konva.Layer({draggable: false});
s1.add(layer1);
// draw a background rect to catch events.
var r1 = new Konva.Rect({x: 0, y: 0, width: 300, height: 200, fill: 'gold' })
layer1.add(r1)
// draw a rectangle to be used as the rubber area
var r2 = new Konva.Rect({x: 0, y: 0, width: 0, height: 0, stroke: 'red', dash: [2,2]})
r2.listening(false); // stop r2 catching our mouse events.
layer1.add(r2)
s1.draw() // First draw of canvas.
var posStart;
var posNow;
var mode = '';
function startDrag(posIn){
posStart = {x: posIn.x, y: posIn.y};
posNow = {x: posIn.x, y: posIn.y};
}
function updateDrag(posIn){
// update rubber rect position
posNow = {x: posIn.x, y: posIn.y};
var posRect = reverse(posStart,posNow);
r2.x(posRect.x1);
r2.y(posRect.y1);
r2.width(posRect.x2 - posRect.x1);
r2.height(posRect.y2 - posRect.y1);
r2.visible(true);
s1.draw(); // redraw any changes.
}
// start the rubber drawing on mouse down.
r1.on('mousedown', function(e){
mode = 'drawing';
startDrag({x: e.evt.layerX, y: e.evt.layerY})
})
// update the rubber rect on mouse move - note use of 'mode' var to avoid drawing after mouse released.
r1.on('mousemove', function(e){
if (mode === 'drawing'){
updateDrag({x: e.evt.layerX, y: e.evt.layerY})
}
})
// here we create the new rect using the location and dimensions of the drawing rect.
r1.on('mouseup', function(e){
mode = '';
r2.visible(false);
var newRect = new Konva.Rect({
x: r2.x(),
y: r2.y(),
width: r2.width(),
height: r2.height(),
fill: 'red',
listening: false
})
layer1.add(newRect);
s1.draw();
})
// reverse co-ords if user drags left / up
function reverse(r1, r2){
var r1x = r1.x, r1y = r1.y, r2x = r2.x, r2y = r2.y, d;
if (r1x > r2x ){
d = Math.abs(r1x - r2x);
r1x = r2x; r2x = r1x + d;
}
if (r1y > r2y ){
d = Math.abs(r1y - r2y);
r1y = r2y; r2y = r1y + d;
}
return ({x1: r1x, y1: r1y, x2: r2x, y2: r2y}); // return the corrected rect.
}
p
{
padding: 4px;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="https://cdn.rawgit.com/konvajs/konva/1.6.5/konva.min.js"></script>
<p>Click & drag on the background to draw a rectangle and fill it.
</p>
<div id='container1' style="display: inline-block; width: 300px, height: 200px; background-color: silver; overflow: hidden; position: relative;"></div>
When adding a canvas element to a page I want the canvas and its contents to scale down as the browser window scales down.
There seem to be several questions asked about this here and with each one I haven't quite found the answer I was looking for. I seem to have something that works and thought I would post it for others to shoot down or improve upon.
In this example I have a page which is 1000px wide at max width. The canvas element is only 800px wide at max width.
HTML:
<div id="container"></div>
CSS:
#container {
background-color: #888888;
display: inline-block;
max-width: 1000px;
}
JavaScript:
var maxStageWidth = 800;
var maxStageHeight = 500;
var maxPageWidth = 1000;
// Check to see if window is less than desired width and calls sizing functions
function setStageWidth() {
if (window.innerWidth < maxPageWidth) {
resizeStage();
} else {
maxStageSize();
};
};
// Sets scale and dimensions of stage in relation to window size
function resizeStage() {
var scalePercentage = window.innerWidth / maxPageWidth;
stage.setAttr('scaleX', scalePercentage);
stage.setAttr('scaleY', scalePercentage);
stage.setAttr('width', maxStageWidth * scalePercentage);
stage.setAttr('height', maxStageHeight * scalePercentage);
stage.draw();
};
//Sets scale and dimensions of stage to max settings
function maxStageSize() {
stage.setAttr('scaleX', 1);
stage.setAttr('scaleY', 1);
stage.setAttr('width', maxStageWidth);
stage.setAttr('height', maxStageHeight);
stage.draw();
};
var stage = new Kinetic.Stage({
container: 'container',
width: maxStageWidth,
height: maxStageHeight,
scaleX: 1
});
var circles = new Kinetic.Layer();
var circleRed = new Kinetic.Circle({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: 100,
stroke: 'black',
strokeWidth: 2,
fill: 'red'
});
var circleBlue = new Kinetic.Circle({
x: stage.getWidth() / 2 + 120,
y: stage.getHeight() / 2 + 175,
radius: 50,
stroke: 'black',
strokeWidth: 2,
fill: 'blue'
});
var circleOrange = new Kinetic.Circle({
x: stage.getWidth() / 2 - 175,
y: stage.getHeight() / 2 + 100,
radius: 75,
stroke: 'black',
strokeWidth: 2,
fill: 'orange'
});
circles.add(circleRed);
circles.add(circleBlue);
circles.add(circleOrange);
stage.add(circles);
// On load we set stage size based on window size
setStageWidth();
// On window resize we resize the stage size
window.addEventListener('resize', setStageWidth);
There doesn't seem to be anything wrong with your functions. Can you explain more of what you're trying to acheive? Shouldn't your Max page width and max stage width be the same number?
Your functions are doing two things: scaling and resizing, but you are focusing on the scale based on the horizontal change. Try changing it to a diagonal scaling factor or scale vertical and horizontal separately.
// Sets scale and dimensions of stage in relation to window size
function resizeStage() {
var horizScalePercentage = window.innerWidth / maxPageWidth;
var vertiScalePercentage = window.innerHeight/ maxPageHeight;
stage.setAttr('scaleX', horizScalePercentage );
stage.setAttr('scaleY', vertiScalePercentage );
stage.setAttr('width', maxStageWidth * horizScalePercentage );
stage.setAttr('height', maxStageHeight * vertiScalePercentage );
stage.draw();
};
//Sets scale and dimensions of stage to max settings
function maxStageSize() {
stage.setAttr('scaleX', 1);
stage.setAttr('scaleY', 1);
stage.setAttr('width', maxStageWidth);
stage.setAttr('height', maxStageHeight);
stage.draw();
};
http://jsfiddle.net/8cw7J/1/ Check this fiddle
I have a DIV container that I want to place inside a Canvas element, how do I set the clipping path of the #canvasContents to the Canvas shape?
<canvas id="myCanvas" width="500" height="400"></canvas>
<div id="canvasContents" width="500" height="400">canvas contents</div>
<script>
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 120, y = 70;
context.beginPath();
context.moveTo(x, y);
context.bezierCurveTo(x, y, x + 6, y - 82, x + 98, y - 25);
context.bezierCurveTo(x + 210, y - 5, x + 325, y + 2, x + 283, y + 78);
context.bezierCurveTo(x + 244, y + 173, x + 237, y + 270, x + 138, y + 235);
context.bezierCurveTo(x - 29, y + 185, x - 145, y + 154, x - 65, y + 99);
context.closePath();
context.lineWidth = 1;
context.fillStyle = '#FFF';
context.fill();
context.strokeStyle = '#000';
context.stroke();
</script>
You can't place anything inside a canvas element. The content inside a canvas element will only show if canvas is not supported in a browser. In other cases it's ignored.
You can try to use SVG to place a div inside by wrapping the code inlined for the SVG but there are some restrictions related to external content.
You need to build an inline SVG like this:
var inlineSVG =
'<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">' +
'<foreignObject width="100%" height="100%">' +
ourHTMLgoesHere +
'</foreignObject></svg>';
Then convert it to blob and url:
var svg = new Blob([inlineSVG], {type:"image/svg+xml;charset=utf-8"});
var url = URL.createObjectURL(svg);
Now you can set this as an image source, load it and then draw it to canvas.
For simplicity I made this function to do all the hard work (please see link above for details). Text can be any HTML including the div you need to wrap inside. Just remember it cannot contain links to external content (images, css, fonts etc.):
/**
* Canvas extension: drawHTMLText(txt, options)
* By Ken Fyrstenberg, Epistemex
* http://epistemex.com/
*
* USAGE:
* myContext.drawHTMLText(txt [, options]);
*
* var options = {x: startPosition,
* y: startPosition,
* width: maxWidth,
* height: maxHeight,
* callback: myFunction,
* callbackError: myErrorFunction}
*
* Each individual option is optional in themself. The callback
* on success contains an object with reference to result and
* originalText. Error callback is provided with the error object.
*
* License: MIT
*/
CanvasRenderingContext2D.prototype.drawHTMLText = function(txt, options) {
/// make sure we have an object if none was provided
options = options || {};
var ctx = this,
/// build inline SVG
iSVG =
'<svg xmlns="http://www.w3.org/2000/svg" width="' +
(options.width ? options.width : ctx.canvas.width) +
'" height="' +
(options.height ? options.height : ctx.canvas.height) +
'"><foreignObject width="100%" height="100%">' +
'<div xmlns="http://www.w3.org/1999/xhtml" style="font:' +
ctx.font + ';color:' + ctx.fillStyle + '">' +
txt +
"</div></foreignObject></svg>",
/// create Blob of inlined SVG
svg = new Blob([iSVG],{type:"image/svg+xml;charset=utf-8"}),
/// create URL (handle prefixed version)
domURL = self.URL || self.webkitURL || self,
url = domURL.createObjectURL(svg),
/// create Image
img = new Image;
/// handle image loading
img.onload = function () {
/// draw SVG to canvas
ctx.drawImage(img,
(options.x ? options.x : 0),
(options.y ? options.y : 0));
domURL.revokeObjectURL(url);
/// invoke callback if provided
if (typeof options.callback === 'function')
options.callback({result: img,
originalText: txt});
};
/// handle potential errors
img.onerror = function(e) {
if (typeof options.callbackError === 'function') {
options.callbackError(e);
} else {
console.log(e);
}
}
img.src = url;
}
If you need clipping just add that to the canvas itself using context.clip() after defining a path.
Live Demo
Here is one way to accomplish it, first I put the canvas element over the div just using absolute positioning like so
canvas {
position:absolute
}
#canvasContents {
position:absolute;
background:blue;
width:500px;
height:400px;
line-height:400px;
text-align:center
}
Then I fill the canvas and use clipping to show the effect.
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var x = 120,
y = 70;
context.fillRect(0, 0, canvas.width, canvas.height);
context.save();
context.beginPath();
context.moveTo(x, y);
context.bezierCurveTo(x, y, x + 6, y - 82, x + 98, y - 25);
context.bezierCurveTo(x + 210, y - 5, x + 325, y + 2, x + 283, y + 78);
context.bezierCurveTo(x + 244, y + 173, x + 237, y + 270, x + 138, y + 235);
context.bezierCurveTo(x - 29, y + 185, x - 145, y + 154, x - 65, y + 99);
context.closePath();
context.clip();
context.clearRect(0, 0, canvas.width, canvas.height);
ctx.restore();
The key with clipping is to save the context, draw your path, and then call clip. After that you can do a fill, or in this example a clearRect which will show whatever is positioned behind the canvas element.
I want to create volume knob using HTML5 and CreateJS. It is almost done. you can see this on following url
http://www.urbantruanthosting.co.uk/radiosimulator/testpage.html
but it is moving on every event of js. And I want to rotate on mouse's pressmove event on both side and currently it's moving clockwise, how can I rotate it in reverse. Please give me suggestion.
Thanks in advance.
and I have used following code.
var bmp = new createjs.Bitmap(image).set({
scaleX: 1,
scaleY: 1,
regX: w / 2,
regY: h / 2,
cursor: "pointer",
x: 305,
y: -90,
rotation: -55
});
bmp.regX = bmp.image.width / 2;
bmp.regY = bmp.image.height / 2;
var movieClip = new createjs.Container();
movieClip.addChild(bmp);
imageContainer.addChild(movieClip);
/*add events to enavle the knob to moveclockwise START*/
bmp.addEventListener("pressmove", function (evt) {
TweenMax.to(bmp, 5, { rotation: 270, repeat: -1, ease: Linear.easeNone });
if (headerCnt == 0) {
audioElement.play();
screen.src = 'images/header_5.jpg';
headerCnt = 5;
screenImage.set({
image: screen
});
}
stage.update();
});
This is where trigonometry comes in handy. Check out the following fiddle. Using the Math.atan2 function, we can calculate the angle of the mouse pointer relative to the center of the dial. Then, we convert radians to degrees and set the rotation of the dial.
dial.addEventListener("pressmove", function(e){
console.log(e);
//Calc Angle
var adj = e.stageX - dialHolder.x;
var opp = e.stageY - dialHolder.y;
var angle = Math.atan2(opp, adj);
angle = angle / (Math.PI / 180);
dial.rotation = angle;
});
Note: The regX and regY points might be slightly off which is why the dial wobbles a bit.
I am struggling to understand why my angles are returning weird angles if anything other than a right angle is drawn. I drew a basic triangle using Canvas in HTML5.
I have the html code and js code to paste here: Please can someone tell me why only these right angles adds up to 180degrees. I have set the js code to output the angles and the sum thereof to the console... so you can see what I am talking about.
You can modify the draw function code to set the position of one of the points to make a right angle.. then you will see the 180 degrees and the angles are correct.
I searched all over the internet for an explanation and checked my formulas. Cant seem to figure this one out.
Thank you very much for any help you can offer..
--- CODE FOR HTML ---
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Canvas - Triangle experiment</title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="js/drawShapes.js"></script>
<style>
* { margin: 0; }
* { padding: 0; }
span.markings {
position: absolute;
}
div.drawingArea {
margin: 50px 0 0 10px;
padding: 0;
width: 500px;
height: 500px;
position: relative;
background: #ccc;
}
.coords { position: absolute; top: 0; left: 200px; }
.coords p { position: relative; }
.xcoord, .ycoord { font-weight: bold; color: red; }
#myCanvas { background: #eee; }
</style>
</head>
<body>
<div class="coords"><p>X: <span class="xcoord"></span></p><p>Y: <span class="ycoord"></span></p></div>
<div class="drawingArea">
<span class="markings A"></span>
<span class="markings B"></span>
<span class="markings C"></span>
<canvas id="myCanvas" width="410" height="410">Your browser does not have support for Canvas. You should see:</canvas>
</div>
</body>
</html>
--- CODE FOR JS ---
$(document).ready(function(){
// Just for dev purposes.. show X and Y coords when inside drawingArea
$('.drawingArea').mousemove(function(e){
$('.xcoord').html(e.pageX -10); // subtract 10 for margin left is 10
$('.ycoord').html(e.pageY -50); // subtract 40 bc margin top is 40
});
draw();
function draw()
{
// Initialize context
createContext('2d');
// Set the style properties.
context.fillStyle = '#fff';
context.strokeStyle = '#FF9900';
context.lineWidth = 5;
// Set initial positions and lengths
pts = {};
pts.AXLoc = 60;
pts.AYLoc = 40;
pts.BXLoc = 360;
pts.BYLoc = 40;
pts.CXLoc = 100;
pts.CYLoc = 340;
// Get difference between points
vector = {};
vector.Ax = Math.abs(pts.AXLoc-pts.BXLoc);
vector.Ay = Math.abs(pts.AYLoc-pts.BYLoc);
vector.Bx = Math.abs(pts.BXLoc-pts.CXLoc);
vector.By = Math.abs(pts.BYLoc-pts.CYLoc);
vector.Cx = Math.abs(pts.CXLoc-pts.AXLoc);
vector.Cy = Math.abs(pts.CYLoc-pts.AYLoc);
console.log(vector.Ax);
console.log(vector.Ay);
console.log(vector.Bx);
console.log(vector.By);
console.log(vector.Cx);
console.log(vector.Cy);
// Find the magnitude of each vector
vector.magA = Math.sqrt(Math.pow(vector.Ax, 2) + Math.pow(vector.Ay, 2));
vector.magB = Math.sqrt((Math.pow((vector.Bx), 2) + Math.pow((vector.By), 2)));
vector.magC = Math.sqrt((Math.pow((vector.Cx), 2) + Math.pow((vector.Cy), 2)));
// Cos A = (A.C) / sqrt(magnitude of A) x (magnited of C)
// This should return radian which is then converted to degrees
// Create function once code works!
vector.angleA = ((vector.Ax * vector.Cx) + (vector.Ay * vector.Cy)) / (vector.magA * vector.magC);
vector.angleA = Math.acos(vector.angleA) * (180/Math.PI);
vector.angleB = ((vector.Ax * vector.Bx) + (vector.Ay * vector.By)) / (vector.magA * vector.magB);
vector.angleB = Math.acos(vector.angleB) * (180/Math.PI);
vector.angleC = ((vector.Bx * vector.Cx) + (vector.By * vector.Cy)) / (vector.magB * vector.magC);
vector.angleC = Math.acos(vector.angleC) * (180/Math.PI);
// Output test data
console.log('angle a = ' + vector.angleA);
console.log('angle b = ' + vector.angleB);
console.log('angle c = ' + vector.angleC);
vector.allangles = vector.angleA + vector.angleB + vector.angleC;
console.log('All angles = ' +vector.allangles ); // only adds up to 180deg if right angle??!!
// Begin drawing
context.beginPath();
// Start from the top-left point.
context.moveTo(pts.AXLoc, pts.AYLoc); // give the (x,y) coordinates
context.lineTo(pts.BXLoc, pts.BYLoc);
context.lineTo(pts.CXLoc, pts.CYLoc);
//context.lineTo(pts.AXLoc, pts.AYLoc); // closes the origin point? alternate way of closing???
context.lineJoin = 'mitre';
context.closePath(); // closes the origin point? good for strokes
// Done! Now fill the shape, and draw the stroke.
// Note: your shape will not be visible until you call any of the two methods.
context.fill();
context.stroke();
context.closePath();
// Set position of markings (spans)
$('span.markings.A').css({
'top' : pts.AYLoc -30,
'left' : pts.AXLoc -5
});
$('span.markings.B').css({
'top' : pts.BYLoc -5,
'left' : pts.BXLoc +10
});
$('span.markings.C').css({
'top' : pts.CYLoc -5,
'left' : pts.CXLoc -25
});
// Write markings onto canvas (degrees and lengths)
$('span.markings.A').html('A');
$('span.markings.B').html('B');
$('span.markings.C').html('C');
}
function createContext(contextType)
{
// Get the canvas element.
var elem = document.getElementById('myCanvas');
if (!elem || !elem.getContext) {
return;
}
// Get the canvas 2d context.
context = elem.getContext(contextType);
if (!context) {
return;
}
}
});
You've got your angle formulas a little wrong. Here's a working fiddle: http://jsfiddle.net/manishie/AgmF4/.
Here are my corrected formulas:
vector.angleA = (Math.pow(vector.magB, 2) + Math.pow(vector.magC, 2) - Math.pow(vector.magA, 2)) / (2 * vector.magB * vector.magC);
vector.angleA = Math.acos(vector.angleA) * (180/Math.PI);
vector.angleB = (Math.pow(vector.magA, 2) + Math.pow(vector.magC, 2) - Math.pow(vector.magB, 2)) / (2 * vector.magA * vector.magC);
vector.angleB = Math.acos(vector.angleB) * (180/Math.PI);
vector.angleC = (Math.pow(vector.magA, 2) + Math.pow(vector.magB, 2) - Math.pow(vector.magC, 2)) / (2 * vector.magA * vector.magB);
vector.angleC = Math.acos(vector.angleC) * (180/Math.PI);