Related
i am using fabricjs with reactjs and when the useEffect call i have initialize the canvas.
and draw a line with two circles top and bottom. when i pick image from computer and select over the lines the background image is removed.
`const refrenceLine = () => {
const canvas = canvasRef.current;
let isDraw = false;
const refrenceLineCircle1 = new fabric.Circle({
left: 50,
top: 50,
stroke: "black",
radius: 10,
fill: "",
transparentCorners: true,
});
refrenceLineCircle1.hasControls = false;
const refrenceCircle2 = new fabric.Circle({
left: 50,
top: 250,
stroke: "black",
radius: 10,
fill: "",
transparentCorners: true,
});
refrenceCircle2.hasControls = false;
const box1point = refrenceLineCircle1.getPointByOrigin("center", "bottom");
const box2point = refrenceCircle2.getPointByOrigin("center", "top");
// console.log("box1point.x1", box1point.x);
// console.log("box1point.y1", box1point.y);
// console.log("box2point.x2", box2point.x);
// console.log("box2point.y2", box2point.y);
const refrenceLineconnector = new fabric.Line(
[box1point.x, box1point.y, box2point.x, box2point.y],
{
stroke: "black",
strokeWidth: 2,
lockScalingX: true,
lockScalingY: true,
lockRotation: true,
hasControls: true,
hasBorders: true,
lockMovementX: true,
lockMovementY: true,
hasRotatingPoint: true,
}
);
refrenceLineconnector.hasControls = false;
refrenceLineCircle1.on("moving", function () {
console.log("here");
const connectPoint = this.getPointByOrigin("center", "bottom");
refrenceLineconnector.set({
x1: connectPoint.x,
y1: connectPoint.y,
});
});
refrenceCircle2.on("moving", function () {
const connectPoint = this.getPointByOrigin("center", "top");
refrenceLineconnector.set({
x2: connectPoint.x,
y2: connectPoint.y,
});
});
canvas.add(refrenceLineCircle1, refrenceCircle2, refrenceLineconnector);
canvas.on("mouse:down", function (e) {
isDraw = true;
console.log("at start", e.target?.fill);
// if (e.target.fill == "green") {
// alert("green circle is clecked");
// } else alert("red cirecle is cleiked");
});
canvas.on("mouse:up", function (e) {
if (!isDraw) return;
// console.log("after end", e.e);
console.log("refrenceLineconnector", refrenceLineconnector);
});
};`
Here is my code to add the pattern to the stroke of the moveable line.
when I try to move the line, the pattern remains in the same position. It should move inside the stroke according to the stroke's angle. Is there any way to adjust the stroke pattern?
When the color is applied to the normal stroke it works fine. Kindly someone suggests how can I rectify this problem. And if there is any other method to make a zigzag line on canvas that can move to and fro, can be resized, and can be rotated according to the requirement just like a normal line.
image used for pattern is attached with the file
window.canvas = canvas;
let pic = 'http://127.0.0.1:5500/sin-small.png'
function loadPattern(url) {
fabric.util.loadImage(url, function(img) {
let pattern = new fabric.Pattern({
source: img,
repeat: 'repeat-x'
});
console.log(pattern)
line.set('stroke', pattern)
canvas.renderAll();
});
}
var canvas = new fabric.Canvas('c', {
selection: true
});
var line = new fabric.Line([50, 50, 100, 100], {
fill: 'red',
stroke: 'red',
strokeWidth: 10,
selectable: true,
hasControls: false,
hasBorders: false,
centeredRotation: false,
centeredScaling: false,
//originX: 'center',
//originY: 'center'
});
var circle1 = new fabric.Circle({
radius: 5,
fill: 'green',
left: 45,
top: 45,
hasControls: false,
hasBorders: false,
name: 'circle1'
});
var circle2 = new fabric.Circle({
radius: 5,
fill: 'green',
left: 95,
top: 95,
hasControls: false,
hasBorders: false,
name: 'circle2'
});
canvas.on('object:moving', function (options) {
var objType = options.target.get('type');
var p = options.target;
if (objType == 'line') {
var _l = line.left;
var _t = line.top;
circle1.set({
'left': (line.calcLinePoints().x1 + _l),
'top': (line.calcLinePoints().y1 + _t)
});
circle1.line.set({
'x1': circle1.left,
'y1': circle1.top
});
circle1.line.setCoords();
circle2.set({
'left': (line.calcLinePoints().x2 + _l),
'top': (line.calcLinePoints().y2 + _t)
});
circle2.line.set({
'x2': circle2.left,
'y2': circle2.top
});
circle2.line.setCoords();
canvas.renderAll();
}
if (objType == 'circle') {
if (p.name == 'circle1') {
line.set({
x1: circle1.getCenterPoint().x, y1: circle1.getCenterPoint().y, selectable: true
});
} else {
if (p.name == 'circle2') {
line.set({
x2: circle2.getCenterPoint().x, y2: circle2.getCenterPoint().y, selectable: true
});
}
}
}
line.setCoords();
circle1.setCoords();
circle2.setCoords();
canvas.renderAll();
});
canvas.add(line);
loadPattern(pic);
circle1.line=line;
circle2.line=line;
canvas.add(circle1);
canvas.add(circle2);
canvas.renderAll();
My project uses echart to create radar chart and i have to find click event for indicators around radar chart.
It is implemented like this.
createradarchart() {
this.theme.getJsTheme()
.pipe(
takeWhile(() => this.alive),
delay(1),
)
.subscribe(config => {
this.options = {
name: 'KPI Radar',
grid: {
left: '5%',
right: '5%',
top: 0,
bottom: 0
},
// label: {
// distance: 5
// },
type: 'radar',
color: ['red', 'green', 'blue'],
legend: {
bottom: 5,
itemGap: 20,
data: ['Baseline', 'Threshold', 'Actual'],
textStyle: {
color: 'black',
fontSize: 10
}
},
radar: {
indicator: this.indicator,
nameGap: 5,
shape: 'circle',
radius: '43%',
name: {
textStyle: {
color: 'black',
fontSize: 10
}
}
},
tooltip: {
show: true,
textStyle: {fontSize:10},
trigger: 'item',
formatter: (params => {
return params['name']+'-'+params['value'][1];
})
},
series: this.seriesdata,
};
this.ctx = this.echartsIntance.getRenderedCanvas();
this.chart = new Chart(this.ctx,{type:'radar', options: this.options})
// this.ctx = canvas.getContext("2d");
});
}
where data and options are in format, with data being fetched from server:
seriesdata: any = {type: 'radar', data:[{name:'Baseline',value:[1,2,3,4,5]},{name:'Threshold',value:[1,2,3,4,5]},{name:'Actual',value:[1,2,3,4,5]}]};
indicator = [
{ name: 'DL User Thpt_Kbps[CDBH]', max: 100 },
{ name: 'ERAB SSR[CDBH]', max: 100 },
{ name: 'PS DCR %[CDBH]', max: 100 },
{ name: 'VoLTE CSSR', max: 100 },
{ name: 'VoLTE DCR[CBBH]', max: 100 }
];
options: EChartOption = {
name: 'KPI Radar',
grid: {
left: '2%',
right: '2%',
top: 0,
bottom: 0
},
// label:{
// distance: 5
// },
type: 'radar',
color: ['red', 'green', 'blue'],
legend: {
orient: 'vertical',
align: 'left',
right: 20,
data: ['Baseline', 'Threshold', 'Actual'],
textStyle: {
color: 'black',
fontSize: 10
}
},
radar: {
indicator: this.indicator,
nameGap: 5,
shape: 'circle',
radius:'60%',
},
tooltip: {
show: false,
// trigger: 'item',
// formatter: (params => {
// return params['name']+'-'+params['value'][1];
// })
}
};
This is where i want click event to be triggered, having the name of label which is clicked.
Approach i found to do this is this, but it didnt work, i debugged and found that scale.pointLabels is empty.
labelClicked(e:any){
var self = this;
var helpers = Chart.helpers;
var scale = self.chart.scale;
var opts = scale.options;
var tickOpts = opts.ticks;
// Position of click relative to canvas.
var mouseX = e.offsetX;
var mouseY = e.offsetY;
var labelPadding = 5; // number pixels to expand label bounding box by
// get the label render position
// calcs taken from drawPointLabels() in scale.radialLinear.js
var tickBackdropHeight = (tickOpts.display && opts.display) ?
helpers.valueOrDefault(tickOpts.fontSize, Chart.defaults.global.defaultFontSize)
+ 5: 0;
var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);
for (var i = 0; i < scale.pointLabels.length; i++) {
// Extra spacing for top value due to axis labels
var extra = (i === 0 ? tickBackdropHeight / 2 : 0);
var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);
// get label size info.
// TODO fix width=0 calc in Brave?
// https://github.com/brave/brave-browser/issues/1738
var plSize = scale._pointLabelSizes[i];
// get label textAlign info
var angleRadians = scale.getIndexAngle(i);
var angle = helpers.toDegrees(angleRadians);
var textAlign = 'right';
if (angle == 0 || angle == 180) {
textAlign = 'center';
} else if (angle < 180) {
textAlign = 'left';
}
// get label vertical offset info
// also from drawPointLabels() calcs
var verticalTextOffset = 0;
if (angle === 90 || angle === 270) {
verticalTextOffset = plSize.h / 2;
} else if (angle > 270 || angle < 90) {
verticalTextOffset = plSize.h;
}
// Calculate bounding box based on textAlign
var labelTop = pointLabelPosition.y - verticalTextOffset - labelPadding;
var labelHeight = 2*labelPadding + plSize.h;
var labelBottom = labelTop + labelHeight;
var labelWidth = plSize.w + 2*labelPadding;
var labelLeft;
switch (textAlign) {
case 'center':
labelLeft = pointLabelPosition.x - labelWidth/2;
break;
case 'left':
labelLeft = pointLabelPosition.x - labelPadding;
break;
case 'right':
labelLeft = pointLabelPosition.x - labelWidth + labelPadding;
break;
default:
console.log('ERROR: unknown textAlign '+textAlign);
}
var labelRight = labelLeft + labelWidth;
// Render a rectangle for testing purposes
self.ctx.save();
self.ctx.strokeStyle = 'red';
self.ctx.lineWidth = 1;
self.ctx.strokeRect(labelLeft, labelTop, labelWidth, labelHeight);
self.ctx.restore();
// compare to the current click
if (mouseX >= labelLeft && mouseX <= labelRight && mouseY <= labelBottom && mouseY >= labelTop) {
alert(scale.pointLabels[i]+' clicked');
// Break loop to prevent multiple clicks, if they overlap we take the first one.
break;
}
}
}
Thanks in advance
Can you show me how to speed up and slow down the speed of the ball using the button when clicked,
I used the code but it hasn't worked yet,
this.upButton = this.add.sprite(230, 530, 'down-bubble').setInteractive({ cursor: 'pointer' });
this.downButton = this.add.sprite(80, 530, 'up-bubble').setInteractive({ cursor: 'pointer' });
this.input.on('gameobjectup', function (pointer, gameobject) {
if (gameobject === this.downButton && this.spinSpeed.timeScale > 100)
{
this.spinSpeed.timeScale -= 10.1;
}
else if (gameobject === this.upButton && this.spinSpeed.timeScale < 19.9)
{
this.spinSpeed.timeScale += 10.1;
}
});
generateDance() {
this.spinSpeed = 0.003;
return this.tweens.addCounter({
from: 220,
to: 160,
duration: 9000,
delay: 2000,
ease: 'Sine.easeInOut',
repeat: -1,
yoyo: true
});
}
generateBalls() {
const hitArea = new Phaser.Geom.Rectangle(0, 0, 32, 32);
const hitAreaCallback = Phaser.Geom.Rectangle.Contains;
const circle = new Phaser.Geom.Circle(400, 300, 220);
const balls = this.add.group(null, {
key: 'balls',
frame: [0, 1, 5],
repeat: 5,
setScale: { x: 3, y: 3 },
hitArea: hitArea,
hitAreaCallback: hitAreaCallback,
});
// console.log(balls.getChildren().length);
this.input.on('gameobjectover', function (pointer, gameObject) {
document.body.style.cursor = 'pointer';
});
this.input.on('gameobjectout', function (pointer, gameObject) {
document.body.style.cursor = 'default';
});
this.upButton = this.add.sprite(230, 530, 'down-bubble').setInteractive({ cursor: 'pointer' });
this.downButton = this.add.sprite(80, 530, 'up-bubble').setInteractive({ cursor: 'pointer' });
this.input.on('gameobjectup', function (pointer, gameobject) {
if (gameobject === this.downButton && this.spinSpeed.timeScale > 100)
{
this.spinSpeed.timeScale -= 10.1;
}
else if (gameobject === this.upButton && this.spinSpeed.timeScale < 19.9)
{
this.spinSpeed.timeScale += 10.1;
}
});
Phaser.Actions.PlaceOnCircle( balls.getChildren(), circle);
return balls;
}
generateDance() {
this.spinSpeed = 0.003;
// https://phaser.discourse.group/t/how-to-create-key-combo-with-custom-buttons/2622
return this.tweens.addCounter({
from: 220,
to: 160,
duration: 9000,
delay: 2000,
ease: 'Sine.easeInOut',
repeat: -1,
yoyo: true
});
}
update() {
Phaser.Actions.RotateAroundDistance( this.balls.getChildren(), { x: 400, y: 300 }, this.spinSpeed, this.dance.getValue());
this.playerEyes.update();
// this.buttonsspeed.update();
}
preload(): void {
this.load.image('sky', './src/games/gewgly/assets/images/sky.png');
this.load.image('up-bubble', './src/games/gewgly/assets/images/up-bubble.png');
this.load.image('down-bubble', './src/games/gewgly/assets/images/down-bubble.png');
this.load.spritesheet('balls', './src/games/gewgly/assets/images/balls.png', { frameWidth: 17, frameHeight: 17 });
}
create(): void {
this.add.image(400, 300, 'sky');
this.balls = this.generateBalls();
this.dance = this.generateDance();
// this.buttonsspeed();
this.playerEyes = new Eye(this.generateEyeArg(200,135,3.0));
}
How can you target certain types of object on the FabricJS canvas.
Such as iText objects only, shapes only or svg objects only.
If we take iText for example I don't mean target one that says 'Hello' and over one that says 'Goodbye' but all iText objects and not shape objects.
In the case of the demo below the mouse:down function should apply to iText and not the rectangle (baring in mind the rectangle may not always have a var rect).
var canvas = this.__canvas = new fabric.Canvas('canvas');
// Example function to apply to 1 type of object only
canvas.on('mouse:down', function(e) {
if (e.target) {
if (!e.target.__corner) {
e.target.toggle('flipX');
canvas.renderAll();
}
e.target.__corner = null;
}
});
// create a rectangle
var rect = new fabric.Rect({
left: 50,
top: 50,
width: 100,
height: 50,
angle: 20,
fill: 'red'
});
// set rectangle gradient
rect.setGradient('fill', {
type: 'linear',
x1: -rect.width / 2,
y1: 0,
x2: rect.width / 2,
y2: 0,
colorStops: {
0: '#ffe47b',
1: 'rgb(111,154,211)'
}
});
canvas.add(rect);
//create text
var text = new fabric.IText('Hello World!',{
top:100,
left:200,
textBackgroundColor: '#000',
fontSize:30,
fill: 'white',
fontWeight: 'bold',
textAlign: 'center',
});
canvas.add(text);
canvas.renderAll();
#canvas { background-color:#f4f4f4; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.9/fabric.js"></script>
<canvas id="canvas" width="400" height="300"></canvas>
To target certain types of object, you'd have to check the object type before flipping it horizontally.
These are some of the object types rect, i-text, path-group etc.
/*** available object types ***/
/*
| Object | Type |
|--------|------------------------------------|
| Shape | rect, circle, polygon and so on... |
| Text | i-text |
| Image | image |
| SVG | path-group |
*/
var canvas = this.__canvas = new fabric.Canvas('canvas');
// mouse event
canvas.on('mouse:down', function(e) {
if (e.target) {
var objType = 'path-group';
if (!e.target.__corner && e.target.type === objType) {
e.target.toggle('flipX');
canvas.renderAll();
}
e.target.__corner = null;
}
});
// create a rectangle
var rect = new fabric.Rect({
left: 50,
top: 50,
width: 100,
height: 50,
angle: 20,
fill: 'red'
});
// set rectangle gradient
rect.setGradient('fill', {
type: 'linear',
x1: -rect.width / 2,
y1: 0,
x2: rect.width / 2,
y2: 0,
colorStops: {
0: '#ffe47b',
1: 'rgb(111,154,211)'
}
});
canvas.add(rect);
//create text
var text = new fabric.IText('Hello World!', {
top: 100,
left: 200,
textBackgroundColor: '#000',
fontSize: 30,
fill: 'white',
fontWeight: 'bold',
textAlign: 'center',
});
canvas.add(text);
// add image
fabric.Image.fromURL('https://i.imgur.com/Q6aZlme.jpg', function(img) {
img.set({
top: 150,
left: 200
})
img.scaleToWidth(100);
img.scaleToHeight(100);
canvas.add(img);
});
// add svg
fabric.loadSVGFromURL('https://istack.000webhostapp.com/drop.svg', function(objects, options) {
var svg = fabric.util.groupSVGElements(objects, options);
svg.set({
top: 150,
left: 40
})
canvas.add(svg);
});
canvas.renderAll();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.9/fabric.js"></script>
<canvas id="canvas" width="400" height="300"></canvas>
Try using e.target.type.
var canvas = this.__canvas = new fabric.Canvas('canvas');
// Example function to apply to 1 type of object only
canvas.on('mouse:down', function(e) {
if (e.target && e.target.type === "i-text") {
if (!e.target.__corner) {
e.target.toggle('flipX');
canvas.renderAll();
}
e.target.__corner = null;
}
});
// create a rectangle
var rect = new fabric.Rect({
left: 50,
top: 50,
width: 100,
height: 50,
angle: 20,
fill: 'red'
});
// set rectangle gradient
rect.setGradient('fill', {
type: 'linear',
x1: -rect.width / 2,
y1: 0,
x2: rect.width / 2,
y2: 0,
colorStops: {
0: '#ffe47b',
1: 'rgb(111,154,211)'
}
});
canvas.add(rect);
//create text
var text = new fabric.IText('Hello World!', {
top: 100,
left: 200,
textBackgroundColor: '#000',
fontSize: 30,
fill: 'white',
fontWeight: 'bold',
textAlign: 'center',
});
canvas.add(text);
canvas.renderAll();
#canvas {
background-color: #f4f4f4;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.9/fabric.js"></script>
<canvas id="canvas" width="400" height="300"></canvas>