drag event is not working with onload function - javascript

When I remove the onload function, the dragend event is fired but the shape is not draw and if I use onload function, the shape is drawn but dragend function is not fired.
window.onload = function ()
{
var shapeId = "";
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: $('#canvas'),
id: 'myPaper',
model: graph,
gridSize: 1
});
joint.shapes.devs.TooledModel = joint.shapes.devs.Model.extend(_.extend({}, joint.plugins.TooledModelInterface, {
markup: '<g class="rotatable"><g class="scalable"><rect class="body"/></g><text class="t"/><g class="inPorts"/><g class="outPorts"/><g class="moveTool"/><g class="resizeTool"/><g class="portsTool"/></g>',
defaults: joint.util.deepSupplement({
type: 'devs.TooledModel',
portsTool: false,
moveTool: false,
resizeTool: false,
position: {x: 200, y: 100},
size: {width: 71, height: 625},
attrs: {
'text': {'font-size': 14, text: '', 'ref-x': .5, 'ref-y': .5, ref: '.body', 'y-alignment': 'middle', 'x-alignment': 'middle', fill: 'black', 'font-weight': 'normal', 'font-family': 'Arial, helvetica, sans-serif'},
rect: {stroke: '#008B8B', fill: '#EEEEEE', 'stroke-width': 2}, '.': {magnet: false},
'.inPorts circle': {type: 'input'},
'.outPorts circle': {type: 'output'},
'.port-body': {r: 3}
}
}, joint.shapes.devs.Model.prototype.defaults)
}
));
joint.shapes.devs.TooledModelView = joint.shapes.devs.ModelView.extend(joint.plugins.TooledViewInterface);
var rect1 = new joint.shapes.devs.TooledModel({
moveTool: true,
position: {x: 100, y: 100},
size: {width: 120, height: 25},
attrs: {
text: {text: 'Skill', fill: 'black', 'font-weight': 'bold'},
rect: {
fill: '#F9F9F9', rx: 7, ry: 15, opacity: .80, 'stroke-width': 0, stroke: '#fff'
}
}
});
graph.addCells([rect1]);
};
var cX, cY, oX, oY;
var x, y;
//This function is not getting called
function createShape(event)
{
var $stageContainer = $("#canvas");
var stageOffset = $stageContainer.offset();
cX = event.clientX;
cY = event.clientY;
oX = stageOffset.left;
oY = stageOffset.top;
x = clientX - offsetX;
y = clientY - offsetY;
console.log(x + " " + y);
}
Html:
<body>
<div id="canvas">
<button class="btn ic_table" draggable="true" ondragend="createShape(event)"></button>
</div>
</body>
Is it a bug? Drag events doesn't work on buttons?

I think the problem might be that joint is overriding the properties of child elements of the <canvas> when it draws your shape there. If you move the <button> element outside of the <canvas>, the ondragend fires:
<body>
<div id="canvas"></div>
<button draggable="true" ondragend="createShape(event)">My Button</button>
</body>
Or did you want the button and the shape to be the same object? In the code above, they're two distinct DOM elements.

Related

Is there any way to add a pattern to the stroke of moveable line

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();

IE11 - Object doesn't support property or method 'contains'

Working with Rappid I encountered an error in IE11 console:
Object doesn't support property or method 'contains'
This error is from an SVGElement not having that method. Same code in Chrome works.
Seems like I need to polyfill for this missing method, but according to MDN docs on contains it is supported from IE9 and up, but is not supported on SVGElement.
Edit: Here is a snippet - try to run in Chrome and in IE11
const joint = window.joint;
let graph = new joint.dia.Graph;
let paper = new joint.dia.Paper({
width: 1500, /*200,*/
height: 1500, /*200,*/
el: $('.paper-container'),
gridSize: 1,
drawGrid: true,
model: graph,
//defaultLink: new joint.shapes.app.Link,
//defaultConnectionPoint: joint.shapes.app.Link.connectionPoint,
interactive: { linkMove: false }
});
$('.paper-container').append(paper.el);
paper.render();
var member = function(x, y, rank, name, background, textColor) {
textColor = textColor || "#000";
var cell = new joint.shapes.org.Member({
position: { x: x, y: y },
attrs: {
'.card': { fill: background, stroke: 'none'},
'.rank': { text: rank, fill: textColor, 'word-spacing': '-5px', 'letter-spacing': 0},
'.name': { text: name, fill: textColor, 'font-size': 13, 'font-family': 'Arial', 'letter-spacing': 0 }
}
});
graph.addCell(cell);
return cell;
};
function link(source, target, breakpoints) {
var cell = new joint.shapes.org.Arrow({
source: { id: source.id },
target: { id: target.id },
vertices: breakpoints,
attrs: {
'.connection': {
'fill': 'none',
'stroke-linejoin': 'round',
'stroke-width': '2',
'stroke': '#4b4a67'
}
}
});
graph.addCell(cell);
return cell;
}
var bart = member(300, 70, 'CEO', 'Bart Simpson', '#30d0c6');
var homer = member(90, 200, 'VP Marketing', 'Homer Simpson', '#7c68fd', '#f1f1f1');
var marge = member(300, 200, 'VP Sales', 'Marge Simpson', '#7c68fd', '#f1f1f1');
var lisa = member(500, 200, 'VP Production' , 'Lisa Simpson', '#7c68fd', '#f1f1f1');
var maggie = member(400, 350, 'Manager', 'Maggie Simpson', '#feb563');
var lenny = member(190, 350, 'Manager', 'Lenny Leonard', '#feb563');
var carl = member(190, 500, 'Manager', 'Carl Carlson', '#feb563');
link(bart, marge, [{x: 385, y: 180}]);
link(bart, homer, [{x: 385, y: 180}, {x: 175, y: 180}]);
link(bart, lisa, [{x: 385, y: 180}, {x: 585, y: 180}]);
link(homer, lenny, [{x:175 , y: 380}]);
link(homer, carl, [{x:175 , y: 530}]);
link(marge, maggie, [{x:385 , y: 380}]);
var rootNode = paper.el.querySelector('.joint-type-org-member');
var card = paper.el.querySelector('.joint-type-org-member .card');
console.log("rootNode.contains = ", rootNode.contains);
console.log("rootNode.contains(card) = ", rootNode.contains(card));
<script src="https://unpkg.com/#babel/polyfill#7.4.4/dist/polyfill.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/lodash/lodash.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/backbone/backbone.js"></script>
<link href="https://resources.jointjs.com/demos/joint/build/joint.css" rel="stylesheet"/>
<script src="https://resources.jointjs.com/demos/joint/build/joint.js"></script>
<div class="paper-container"></div>
Looking for a proper Polyfill I found this one
In case the link doesn't work, here is the code:
SVGElement.prototype.contains = function contains(node) {
if (!(0 in arguments)) {
throw new TypeError('1 argument is required');
}
do {
if (this === node) {
return true;
}
} while (node = node && node.parentNode);
return false;
};
Edit
Here is the snippet from the question along with the polyfill suggested
const joint = window.joint;
let graph = new joint.dia.Graph;
let paper = new joint.dia.Paper({
width: 1500, /*200,*/
height: 1500, /*200,*/
el: $('.paper-container'),
gridSize: 1,
drawGrid: true,
model: graph,
//defaultLink: new joint.shapes.app.Link,
//defaultConnectionPoint: joint.shapes.app.Link.connectionPoint,
interactive: { linkMove: false }
});
$('.paper-container').append(paper.el);
paper.render();
var member = function(x, y, rank, name, background, textColor) {
textColor = textColor || "#000";
var cell = new joint.shapes.org.Member({
position: { x: x, y: y },
attrs: {
'.card': { fill: background, stroke: 'none'},
'.rank': { text: rank, fill: textColor, 'word-spacing': '-5px', 'letter-spacing': 0},
'.name': { text: name, fill: textColor, 'font-size': 13, 'font-family': 'Arial', 'letter-spacing': 0 }
}
});
graph.addCell(cell);
return cell;
};
function link(source, target, breakpoints) {
var cell = new joint.shapes.org.Arrow({
source: { id: source.id },
target: { id: target.id },
vertices: breakpoints,
attrs: {
'.connection': {
'fill': 'none',
'stroke-linejoin': 'round',
'stroke-width': '2',
'stroke': '#4b4a67'
}
}
});
graph.addCell(cell);
return cell;
}
var bart = member(300, 70, 'CEO', 'Bart Simpson', '#30d0c6');
var homer = member(90, 200, 'VP Marketing', 'Homer Simpson', '#7c68fd', '#f1f1f1');
var marge = member(300, 200, 'VP Sales', 'Marge Simpson', '#7c68fd', '#f1f1f1');
var lisa = member(500, 200, 'VP Production' , 'Lisa Simpson', '#7c68fd', '#f1f1f1');
var maggie = member(400, 350, 'Manager', 'Maggie Simpson', '#feb563');
var lenny = member(190, 350, 'Manager', 'Lenny Leonard', '#feb563');
var carl = member(190, 500, 'Manager', 'Carl Carlson', '#feb563');
link(bart, marge, [{x: 385, y: 180}]);
link(bart, homer, [{x: 385, y: 180}, {x: 175, y: 180}]);
link(bart, lisa, [{x: 385, y: 180}, {x: 585, y: 180}]);
link(homer, lenny, [{x:175 , y: 380}]);
link(homer, carl, [{x:175 , y: 530}]);
link(marge, maggie, [{x:385 , y: 380}]);
if (window.SVGElement && !SVGElement.prototype.contains) {
SVGElement.prototype.contains = function (node) {
if (!(0 in arguments)) {
throw new TypeError('1 argument is required');
}
do {
if (this === node) {
return true;
}
} while (node = node && node.parentNode);
return false;
};
}
var rootNode = paper.el.querySelector('.joint-type-org-member');
var card = paper.el.querySelector('.joint-type-org-member .card');
console.log("rootNode.contains = ", rootNode.contains);
console.log("rootNode.contains(card) = ", rootNode.contains(card));
<script src="https://unpkg.com/#babel/polyfill#7.4.4/dist/polyfill.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/lodash/lodash.js"></script>
<script src="https://resources.jointjs.com/demos/joint/node_modules/backbone/backbone.js"></script>
<link href="https://resources.jointjs.com/demos/joint/build/joint.css" rel="stylesheet"/>
<script src="https://resources.jointjs.com/demos/joint/build/joint.js"></script>
<div class="paper-container"></div>
Here is also another polyfill that is slightly simpler. That seems to work for me on IE11
if (!SVGElement.prototype.contains) {
SVGElement.prototype.contains = HTMLDivElement.prototype.contains;
}
I found this polyfill here

FabricJS apply function only to certain types of object

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>

jCanvas - background image disappears

im use this http://projects.calebevans.me/jcanvas/
and im have simple example
<input type="button" class="bt" value="draw"/><br>
<canvas id="picture" width=1350 height=1350></canvas>
and js
var canvas = document.getElementById("picture");
var ctx = canvas.getContext('2d');
var img = new Image();
img.src = "tank_usa.jpg";
img.onload = function(){
ctx.drawImage(img, 0, 0);
}
$(".bt").on("click",function(){
// Draw a resizable image
$('#picture').addLayer({
type: 'image',
draggable: true,
source: 'facesSmall.png',
fillStyle: '#fff',
strokeStyle: '#c33',
strokeWidth: 2,
x: 180, y: 150,
width: 200, height: 125,
handle: {
type: 'arc',
fillStyle: '#fff',
strokeStyle: '#c33',
strokeWidth: 2,
radius: 10
}
})
.drawLayer();
})
if im click on button bt,and hover canvas div, my background disappears
how i can do what new image draw over background
Your background gets erased because you are using ctx.drawImage, which does not create a jCanvas layer. jCanvas layers and non-layers cannot exist on the same canvas, because when jCanvas redraws the canvas (manually via drawLayers() or automatically when events are triggered), non-layers will be erased.
To fix this, simply draw "tank_usa.jpg" like you drew 'facesSmall.png': using addLayer with type: 'image' set.
$('#picture').addLayer({
type: 'image',
source: 'tank_usa.jpg',
x: 0, y: 0,
fromCenter: false
});
$(".bt").on("click",function(){
// Draw a resizable image
$('#picture').addLayer({
type: 'image',
draggable: true,
source: 'facesSmall.png',
fillStyle: '#fff',
strokeStyle: '#c33',
strokeWidth: 2,
x: 180, y: 150,
width: 200, height: 125,
handle: {
type: 'arc',
fillStyle: '#fff',
strokeStyle: '#c33',
strokeWidth: 2,
radius: 10
}
})
.drawLayer();
});

Making custom input range in canvas using KonvaJs

i need an input type range in canvas for some purposes, i need to use that to change my fontsize. I already make the shape and also drag able, but the circle controller go beyond the line.
Just preview the bin to see what i mean. Jsbin
i want to limit the draging area to the line only like the input range works.
This is the documentation of KonvaJs library.
this is working, coded by Lavrton
Source
var width = window.innerWidth;
var height = window.innerHeight;
var stage = new Konva.Stage({
container: 'container',
width: width,
height: height
});
var layer = new Konva.Layer();
var Track = new Konva.Line({
x: 44,
y: 55,
points: [60, 0, 0, 0, 0, 0, 0, 0],
stroke: '#BDC3C7',
strokeWidth: 6,
visible: true,
name: 'TrackLine',
lineCap: 'sqare',
lineJoin: 'sqare'
});
var TrackBall = new Konva.Circle({
x: 44,
y: 55,
stroke: '#D35400',
fill: '#ddd',
strokeWidth: 2,
name: 'TrackControl',
radius: 8,
draggable: true,
dragOnTop: false,
visible: true,
dragBoundFunc: function(pos) {
console.log(pos.x, Math.min(44, pos.x))
return {
x: Math.min(104, Math.max(44, pos.x)),
y: this.getAbsolutePosition().y
};
}
});
layer.add(Track);
layer.add(TrackBall);
stage.add(layer);
<script src="https://cdn.rawgit.com/konvajs/konva/0.10.0/konva.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container" class="CanCont"></div>

Categories