How can i set a custom cursor for fabric object? - fabricjs

This is not Drawing Mode.
I want according to some condition to be able to change the cursor when I am over some element. Something like
$('#canvasID').css('cursor','pointer');
but this is not working for me. Do you know some property from their library?

After some tests this is working for me:
canvas.observe('mouse:over', function (e) {
if (e.target.get('type') == 'line') {
e.target.hoverCursor = 'crosshair';
}
});

FabricJS have an in-built mechanism for setting custom cursor (unfortunatelly only for hover and move events):
var canvas = new fabric.Canvas('myCanvas');
var circle = new fabric.Circle({
radius: 20, fill: 'red', left: 10, top: 10
});
circle.hoverCursor = 'no-drop';
canvas.add(circle);
More cursor types you can find here.

Related

How to make a tooltip appear when hovering mouse over a Phaser.GameObject.Image?

In my Phaser 3 game I'm using Phaser.GameObjects.Image 's as things that a user can click on. When a user's mouse hovers over an image I would like a tooltip with text to fade in and appear. When the mouse moves off the image, I'd like the tooltip to disappear.
How can I implement this behavior in Phaser? I'm new to Phaser and I don't see a ToolTip class in the framework.
You could:
use the pointer events for detecting, that the pointer is over an object
and animate/tween the alpha property on the over event
you can alter the speed with the tween duration
and hide the toolTip on the out event
Here the docs to the Input events: https://photonstorm.github.io/phaser3-docs/Phaser.Input.Events.html
Here a mini example:
var config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: {
create: create
}
};
var game = new Phaser.Game(config);
var toolTip;
var toolTipText;
function create ()
{
let objectWithToolTip = this.add.rectangle( 100, 100, 100, 100, 0xffffff).setInteractive();
toolTip = this.add.rectangle( 0, 0, 250, 50, 0xff0000).setOrigin(0);
toolTipText = this.add.text( 0, 0, 'This is a white rectangle', { fontFamily: 'Arial', color: '#000' }).setOrigin(0);
toolTip.alpha = 0;
this.input.setPollOnMove();
this.input.on('gameobjectover', function (pointer, gameObject) {
this.tweens.add({
targets: [toolTip, toolTipText],
alpha: {from:0, to:1},
repeat: 0,
duration: 500
});
}, this);
this.input.on('gameobjectout', function (pointer, gameObject) {
toolTip.alpha = 0;
toolTipText.alpha = 0;
});
objectWithToolTip.on('pointermove', function (pointer) {
toolTip.x = pointer.x;
toolTip.y = pointer.y;
toolTipText.x = pointer.x + 5;
toolTipText.y = pointer.y + 5;
});
}
<script src="//cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.min.js"></script>
Info: if you want to dig deeper into the phaser events you can checkout some examples on the offical home page: https://phaser.io/examples/v3/category/input/mouse are really good, and explore may use cases.
Extra Info: If you don't want to re-invent the wheel, there are several plugins, that can be loaded into phaser(that add special functionality to phaser).
It is always good to check this page(https://phaserplugins.com/), before implementing so common feature/function. There is even on specially for tooltips https://github.com/netgfx/Phaser-tooltip

FabricJS double click new techniques?

could someone please point me in the direction for how to enable double click on fabric images? i came across this solution
FabricJS double click on objects
I am trying to not use FabicjsEx
but i am unable to get anything to work correctly. can someone please let me know the best way to accomplish this?
The best way to accomplish this, is to use fabric.util.addListener method.
Using that you could add a double click event for the canvas element and to restrict it to any particular object ( ie. image ), you would have to check whether you clicked on an image object or not before performing any action.
ᴅᴇᴍᴏ
var canvas = new fabric.Canvas('canvas');
// add image
fabric.Image.fromURL('https://i.imgur.com/Q6aZlme.jpg', function(img) {
img.set({
top: 50,
left: 50
})
img.scaleToWidth(100);
img.scaleToHeight(100);
canvas.add(img);
});
// add rect (for demo)
var rect = new fabric.Rect({
left: 170,
top: 50,
width: 100,
height: 100,
fill: '#07C'
});
canvas.add(rect);
// mouse event
fabric.util.addListener(canvas.upperCanvasEl, 'dblclick', function(e) {
if (canvas.findTarget(e)) {
const objType = canvas.findTarget(e).type;
if (objType === 'image') {
alert('double clicked on a image!');
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.9/fabric.js"></script>
<canvas id="canvas" width="320" height="200"></canvas>

Fabricjs How to scale object but keep the border (stroke) width fixed

I'm developing a diagram tool based on fabricjs. Our tool has our own collection of shape, which is svg based. My problem is when I scale the object, the border (stroke) scale as well. My question is: How can I scale the object but keep the stroke width fixed. Please check the attachments.
Thank you very much!
Here is an easy example where on scale of an object we keep a reference to the original stroke and calculate a new stroke based on the scale.
var canvas = new fabric.Canvas('c', { selection: false, preserveObjectStacking:true });
window.canvas = canvas;
canvas.add(new fabric.Rect({
left: 100,
top: 100,
width: 50,
height: 50,
fill: '#faa',
originX: 'left',
originY: 'top',
stroke: "#000",
strokeWidth: 1,
centeredRotation: true
}));
canvas.on('object:scaling', (e) => {
var o = e.target;
if (!o.strokeWidthUnscaled && o.strokeWidth) {
o.strokeWidthUnscaled = o.strokeWidth;
}
if (o.strokeWidthUnscaled) {
o.strokeWidth = o.strokeWidthUnscaled / o.scaleX;
}
})
canvas {
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
<canvas id="c" width="600" height="600"></canvas>
There is a property called: strokeUniform
Use it like this
shape.set({stroke: '#f55b76', strokeWidth:2, strokeUniform: true })
I have found what feels like an even better solution, works really well with SVG paths.
You can override fabricjs' _renderStroke method and add ctx.scale(1 / this.scaleX, 1 / this.scaleY); before ctx.stroke(); as shown below.
fabric.Object.prototype._renderStroke = function(ctx) {
if (!this.stroke || this.strokeWidth === 0) {
return;
}
if (this.shadow && !this.shadow.affectStroke) {
this._removeShadow(ctx);
}
ctx.save();
ctx.scale(1 / this.scaleX, 1 / this.scaleY);
this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke);
this._applyPatternGradientTransform(ctx, this.stroke);
ctx.stroke();
ctx.restore();
};
You may also need to override fabric.Object.prototype._getTransformedDimensions to adjust the bounding box to account for the difference in size.
Also a more complete implementation would probably add a fabric object property to conditionally control this change for both overridden methods.
Another way is to draw a new object on scaled and remove the scaled one.
object.on({
scaled: function()
{
// store new widht and height
var new_width = this.getScaledWidth();
var new_height = this.getScaledHeight();
// remove object from canvas
canvas.remove(this);
// add new object with same size and original options like strokeWidth
canvas.add(new ...);
}
});
Works perfect for me.

openlayers polygon change color

i'm using OL3 and javascript to draw several polygon on a map. Each polygon came from a database in WKT format like "POLIGON((39 -9, ....))". I can draw them on the map but i want to change fill color of each one, but don't know how to do it.
Here is my code:
//WKTpoly -> this is my array of POLYLINES
var format = new ol.format.WKT();
var vectorArea = new ol.source.Vector({});
for (var i=0;i<WKTpoly.length;i++) {
var featureGeom = format.readFeature(WKTpoly[i]);
featureGeom.getGeometry().transform('EPSG:4326', 'EPSG:3857');
vectorArea.addFeature(featureGeom);
}
VectorMap = new ol.layer.Vector({
name: map,
source: vectorArea,
});
map.addLayer(VectorMap);
Well, after LessThanJake response and some more google search, i found the solution, i had to create a style and call setStyle() before addFeature():
(...)
var style = new ol.style.Style({
fill: new ol.style.Fill({
color: FillColor,
weight: 1
}),
stroke: new ol.style.Stroke({
color: LineColor,
width: 1
})
});
featureGeom.setStyle(style);
(...)
Thanks LessThanJake for pointing the right direction.
Or you can setup the layer to use a function as style
the function signature is
var makeStyle = function(feature,resolution) {
return [styles];
};
You can use this to manage style by feature and resolution (zoom level).
As the function is called at each feature render, you'll need to cache the style in a js object to gain performance.

What can I get a handle on the target of a fabric js event?

In this fabricjs tutorial section it says putting listeners right on an object like so
var rect = new fabric.Rect({ width: 100, height: 50, fill: 'green' });
rect.on('selected', function() {
console.log('selected a rectangle');
});
That is fine, but I don't want to log a string to the console. I want to manipulate the rectangle. Specifically the rectangle isn't selectable by default and based on application state, I need to make it selectable.
I can't figure out how to get a handle on the rectangle from inside the event handler. How to do that escapes me.
In the example you gave, you have attached the event to the object itself. So you can access the object using this or the variable name (which is rect in your case). Here is an example
var rect = new fabric.Rect({ width: 100, height: 50, fill: 'green' });
rect.on('selected', function() {
console.log(this);
this.set({width:200});
});
Alternatively, if you attach it to the canvas so that it listens to all the object:selected events, you can access the object at which the event occurred like this:
var rect = new fabric.Rect({ width: 100, height: 50, fill: 'green' });
canvas.on('object:selected', function (e) {
console.log('selected a rectangle');
e.target.set({width:200});
});

Resources