I am using the following to change the style of the cursor when the mouse is over the circle:
circle1.on('mouseover', function () {
document.body.style.cursor = 'pointer';
});
circle1.on('mouseout', function () {
document.body.style.cursor = 'default';
});
It works great if I draw the circle using:
var circle1 = new Kinetic.Circle({
x: 512,
y: 512,
radius: 140,
stroke: '#00ffff',
strokeWidth: 4,
opacity: 0.5
});
However if I use:
var circle1 = new Kinetic.Circle({
drawFunc: function (canvas) {
var context1 = canvas.getContext();
context1.beginPath();
context1.arc(512, 512, this.getRadius(), 0, 2 * Math.PI, false);
context1.lineWidth = this.getStrokeWidth();
context1.strokeStyle = this.getStroke();
context1.stroke();
},
radius: 140,
stroke: '#00ffff',
strokeWidth: 15,
opacity: 0.5
});
It does not work! The cursor does not change its style; can we just use radius for mouse over. I would appreciate your suggestions, thanks in advance.
As I know you also need to define "drawHitFunc":
circle1.setDrawHitFunc(function (canvas) {
var context2 = canvas.getContext();
context2.beginPath();
context2.arc(100, 100, this.getRadius(), 0, 2 * Math.PI, false);
context2.closePath();
canvas.fillStroke(this);
});
Example: http://jsfiddle.net/lavrton/4DJdU/1/
no, you just need to correctly structure the drawFunc when creating custom shapes. Here's an example:
http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-shape-tutorial/
The problem is that you're using context.stroke(). You need to use canvas.stroke(this);
Anytime you actually render something, like strokes and fills, you need to use the canvas renderer object because it draws onto both the scene graph (what you see) and a specialized hit graph (used for event detection)
Docs:
http://kineticjs.com/docs/symbols/Kinetic.Canvas.php
Related
is there any way to add a shape in KonvaJS which draws outside of it's boundries? Basically a "hole" in the layer, so that I can highlight a spot in the canvas by making everything around a circle darker (black with low opacity).
Any help is much appreciated!
Cheers
Edit:
Here is an image of what I mean (I'm not allowed to embed it yet):
https://i.imgur.com/gvTqgN0.jpg
I was hoping there might be something like this:
Konva.Circle({
x: 100,
y: 100,
radius: 50,
opacity: 0.3,
fill: 'black',
inverted: true
})
and this would then in turn "not draw" a circle, but everything around it would then take the given attributes. In this case it would all be darkend a bit besides the circle.
You can do this with a custom shape:
const shape = new Konva.Shape({
width: stage.width(),
height: stage.height(),
// what is color of background ?
fill: 'rgba(0,0,0,0.2)',
sceneFunc: (ctx, shape) => {
// draw background
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(shape.width(), 0);
ctx.lineTo(shape.width(), shape.height());
ctx.lineTo(0, shape.height());
ctx.lineTo(0, 0);
// now cut circle from the background
// we can do this by useing arc
const x = 200;
const y = 200;
const radius = 10;
// but it must be counter-clockwise
// so the last argument true is very important here
ctx.arc(200, 200, 100, 0, Math.PI * 2, true);
ctx.fillStrokeShape(shape);
},
// remove shape from hit graph, so it is not visible for events
listening: false
});
Demo: https://jsbin.com/tevejujafi/3/edit?html,js,output
As I understand I have to use one canvas for both mapbox Gl and p5.
But how to do this? And what if I have p5 animation will it overwrite the canvas with map?
Any example or hint? Thanks.
My code, but nothing serious
mapboxgl.accessToken = 'pk.***';
var mapGL = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/light-v9',
center: [-120.36603539685188, 50.68667605749022],
zoom: 11.6
});
var mainCanvas;
function setup() {
mainCanvas = createCanvas(720, 400, WEBGL);
}
function draw() {
background(102);
rotate(frameCount / 100.0);
rect(30, 20, 25, 25);
}
Different drawing libraries don't usually play nice with each other on the same canvas. You could try something like overlaying the P5.js canvas on top of the mapbox canvas.
Better yet, use a map library that's already compatible with P5.js, like Mappa or p5.tiledmap. That allows you to draw a map inside P5.js, which makes drawing on top of it much easier.
This is a very old question, but for whoever revisits this question looking for an option... nowadays this could be easily done with the latest version of threebox and a few lines of code. The result looks like this:
<script>
mapboxgl.accessToken = 'pk.eyJ1IjoianNjYXN0cm8iLCJhIjoiY2s2YzB6Z25kMDVhejNrbXNpcmtjNGtpbiJ9.28ynPf1Y5Q8EyB_moOHylw';
var origin = [2.294514, 48.857475];
var map = new mapboxgl.Map({
container: 'map',
style: 'mapbox://styles/mapbox/satellite-v9',
center: origin,
zoom: 18,
pitch: 60,
bearing: 0
});
map.on('style.load', function () {
map
.addLayer({
id: 'custom_layer',
type: 'custom',
renderingMode: '3d',
onAdd: function (map, mbxContext) {
window.tb = new Threebox(
map,
mbxContext,
{
defaultLights: true,
}
);
// import tower from an external glb file, downscaling it to real size
// IMPORTANT: .glb is not a standard MIME TYPE, you'll have to add it to your web server config,
// otherwise you'll receive a 404 error
var options = {
obj: '/3D/eiffel/eiffel.glb',
type: 'gltf',
scale: 0.01029,
units: 'meters',
rotation: { x: 0, y: 0, z: 0 }, //default rotation
adjustment: { x: -0.5, y: -0.5, z: 0 } // place the center in one corner for perfect positioning and rotation
}
tb.loadObj(options, function (model) {
model.setCoords(origin); //position
model.setRotation({ x: 0, y: 0, z: 45.7 }); //rotate it
tb.add(model);
})
},
render: function (gl, matrix) {
tb.update();
}
});
})
</script>
When I add an image in canvas and I do a transformMatrix to the image, the roundingBox is shifted.
Look my jsfiddle : http://jsfiddle.net/ULsr4/2/
canvas = this.__canvas = new fabric.Canvas('canvas');
fabric.Image.fromURL('http://icons.iconarchive.com/icons/archigraphs/lovely-bones/256/Tree-icon.png', function(img) {
img.transformMatrix = [1, 0, 0.7, 1, 0, 0];
canvas.add(img);
img.setCoords();
});
canvas.renderAll();
can someone help me ?
Don't know if it still needed for you but try to use group object inside you fabric.Image.fromURL callback, ie:
var group = new fabric.Group([img], {
left: 10,
top: 10
});
canvas.add(group);
group.setCoords();
My demo is here http://jsfiddle.net/akuma/7NmXw/1/
First, draw something in the blue box.
Then, click the rotate button once.
After the box has been rotated, draw something again.
Finally the draw poisitoin was wrong.
How can I fix that, thanks!
Code:
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer({
width: 400,
height: 400
});
var rect = new Kinetic.Rect({
x: 0,
y: 0,
width: 400,
height: 300,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 5
});
layer.add(rect);
stage.add(layer);
$(document).on('click', '#rotateBtn', function () {
var w = layer.getWidth(),
h = layer.getHeight();
layer.setOffset(w / 2, h / 2);
layer.setPosition(w / 2, h / 2);
layer.rotateDeg(90);
layer.draw();
});
var points = [],
drawing = false;
stage.on('mousedown', function () {
drawing = true;
var pos = stage.getMousePosition();
points.push([pos.x, pos.y]);
var line = new Kinetic.Line({
id: 'line',
points: [
[pos.x, pos.y],
[pos.x + 1, pos.y + 1]
],
stroke: 'white',
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.drawScene();
});
stage.on('mousemove', function () {
if (!drawing) {
return;
}
// Remove previous line
layer.get('#line').remove();
var pos = stage.getMousePosition();
points.push([pos.x, pos.y]);
// Redraw line
var line = new Kinetic.Line({
id: 'line',
points: points,
stroke: 'white',
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.drawScene();
});
stage.on('mouseup', function () {
drawing = false;
points = [];
});
Even after rotating, Kinetic will still give you un-rotated mouse coordinates
That’s because you are asking for stage.getMousePosition and the stage is not rotated.
There is no method like layer.getMousePosition, so you’ll have to create one.
If you rotate your layer 90-degrees, you must also rotate stage's mouse coordinates by 90-degrees.
Here’s how you rotate the stage mouse position to match the layer rotation:
// get the unrotated mouse position from Kinetic
var pos=stage.getMousePosition();
// rotate that point to match the layer rotation
var x1 = rotationX
+ (pos.x-rotationX)*rotationCos
+ (pos.y-rotationY)*rotationSin;
var y1 = rotationY
+ (pos.y-rotationY)*rotationCos
- (pos.x-rotationX)*rotationSin;
Since you will be doing this math with each mousemove, you should pre-calculate the rotation values to maximize performance:
// reset the current rotation information
function setRotation(degrees){
var radians=layer.getRotation();
rotationX=layer.getOffsetX();
rotationY=layer.getOffsetY();
rotationCos=Math.cos(radians);
rotationSin=Math.sin(radians);
}
Also, a bit off-topic to your question, but...
Instead of removing / recreating a new line on every mousemove, you can “recycle” your existing line:
// set the points property of the line to your updated points array
line.setPoints(points);
Here’s code and a Fiddle: http://jsfiddle.net/m1erickson/cQATv/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Prototype</title>
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script src="http://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.5.5.min.js"></script>
<style>
#container{
border:solid 1px #ccc;
margin-top: 10px;
width:400px;
height:400px;
}
</style>
<script>
$(function(){
var stage = new Kinetic.Stage({
container: 'container',
width: 500,
height: 500
});
var layer = new Kinetic.Layer({width:400,height:400});
stage.add(layer);
// vars to save the current rotation information
var rotationX;
var rotationY;
var rotationCos;
var rotationSin;
setRotation(0);
var rect = new Kinetic.Rect({
x: 0,
y: 0,
width: 400,
height: 300,
fill: '#00D2FF',
stroke: 'black',
strokeWidth: 5
});
layer.add(rect);
stage.add(layer);
$(document).on('click', '#rotateBtn', function () {
var w = layer.getWidth(),
h = layer.getHeight();
layer.setOffset(w / 2, h / 2);
layer.setPosition(w / 2, h / 2);
layer.rotateDeg(90);
layer.draw();
// set the info necessary to un-rotate the mouse position
setRotation(layer.getRotationDeg())
});
var points = [],
drawing = false;
stage.on('mousedown', function () {
drawing = true;
// get the rotated mouse position
pos=getPos();
points.push([pos.x, pos.y]);
var line = new Kinetic.Line({
id: 'line',
points: [
[pos.x, pos.y],
[pos.x + 1, pos.y + 1]
],
stroke: 'white',
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.drawScene();
});
stage.on('mousemove', function () {
if (!drawing) {
return;
}
// Remove previous line
layer.get('#line').remove();
// get the rotated mouse position
var pos = getPos();
points.push([pos.x, pos.y]);
// Redraw line
var line = new Kinetic.Line({
id: 'line',
points: points,
stroke: 'white',
strokeWidth: 5,
lineCap: 'round',
lineJoin: 'round'
});
layer.add(line);
layer.drawScene();
});
stage.on('mouseup', function () {
drawing = false;
points = [];
});
// reset to the current rotation information
function setRotation(degrees){
var radians=layer.getRotation();
rotationX=layer.getOffsetX();
rotationY=layer.getOffsetY();
rotationCos=Math.cos(radians);
rotationSin=Math.sin(radians);
}
// rotate the stage mouse position
// to match the layer rotation
function getPos(x,y){
// normal space, no adjustment necessary
if(rotationCos==0){return;}
var pos=stage.getMousePosition();
var x1 = rotationX
+ (pos.x-rotationX)*rotationCos
+ (pos.y-rotationY)*rotationSin;
var y1 = rotationY
+ (pos.y-rotationY)*rotationCos
- (pos.x-rotationX)*rotationSin;
return({x:x1,y:y1});
}
}); // end $(function(){});
</script>
</head>
<body>
<button id="rotateBtn">rotate</button>
<div id="container"></div>
</body>
</html>
I want to draw a hexagon and show an image inside that using html5.
I have tried it out but I am not getting image as the result.
I want to use kineticjs only for this.
Here is the code:
function hexagon(){
var stage = new Kinetic.Stage({
container: "container"
});
var layer = new Kinetic.Layer();
var hexagon = new Kinetic.RegularPolygon({
x: 100,
y: 100,
sides: 6,
radius: 100,
fill: {image: "css/images/logo.png"},
stroke: "royalblue",
strokeWidth: 2
});
// add the shape to the layer
layer.add(hexagon);
// add the layer to the stage
stage.add(layer);
}
fill takes an image object. Try the following:
var layer = new Kinetic.Layer();
logo = new Image();
logo.src = "css/images/logo.png";
var hexagon = new Kinetic.RegularPolygon({
x: 100,
y: 100,
sides: 6,
radius: 100,
fill: {image: logo},
stroke: "royalblue",
strokeWidth: 2
});
// add the shape to the layer
layer.add(hexagon);
// add the layer to the stage
stage.add(layer);
}
The author of KinectJS has written some really great tutorials. In this one he draws an image in a pentagon, as well as a few other things. Should be enough to help you.
http://www.html5canvastutorials.com/kineticjs/html5-canvas-set-fill-with-kineticjs/
I have got the solution.
Posting it late (better late than never)
It should be:
fill: {image: "css/images/logo.png", offset: [0, 0]}