Using Raphaël from a jQuery call - javascript

I'm trying to create a simple application for drawing a graph based on user input. I'm using Raphaël and jQuery. I'd like to have the user give their input on a form, and then draw the SVG graphic. The problem I'm having is that when I call the draw function from within a jQuery click event, the SVG object flickers and then disappears. There's a MWE below. (Perhaps it could be more minimal.) How can I make sure that the graphic stays there after the button click?
<!doctype html>
<html>
<head>
<title>Example</title>
<meta charset="utf-8"/>
<script type="text/javascript" src="jquery-ui-1.10.4/jquery-1.10.2.js"></script>
<script type="text/javascript" src="jquery-ui-1.10.4/ui/jquery-ui.js"></script>
<link rel="stylesheet" href="jquery-ui-1.10.4/themes/base/jquery-ui.css" />
<script type="text/javascript" src="raphael-min.js"></script>
</head>
<body>
<form>
<button id="generate-button">Generate</button>
</form>
<div id="canvas"/>
<script>
function CustomObject() {
this.draw = function() {
// Creates canvas 320 × 200 at 10, 50
paper = Raphael("canvas", 100, 100 );
boundary = window.paper.rect( 5, 5, 25, 25 );
boundary.attr("stroke-dasharray" , "--" );
// Creates circle at x = 50, y = 40, with radius 10
circle = paper.circle(50, 40, 10);
// Sets the fill attribute of the circle to red (#f00)
circle.attr("fill", "#f00");
// Sets the stroke attribute of the circle to white
circle.attr("stroke", "#fff");
}
}
var plot = new CustomObject();
// plot.draw(); // if I call it here, the scene is drawn "normally"
$( "#generate-button" )
.button()
.click(function() {
plot.draw(); // when I call it here, the SVG flickers and disappears
});
</script>
</body>
</html>

The default type for a button is submit and when inside a form will try to submit the form.
Your click handler is executing and then submitting the form which is causing the flicker.
Either take the button out of the form or return false from the click event handler as this will disable the browsers default action.

Related

Draw circles on two different canvases

I have two canvases. I'd like to draw a green circle on the first canvas when clicking on it and a red circle when clicking on the other canvas.
The code below works only for the first canvas. I'd like to know how I can pull off my original idea.
HTML:
<!DOCTYPE html>
<html>
<head>
*** Import jQuery + Paper.js ***
</head>
<body>
<canvas id='firstCanvas'></canvas>
<canvas id='secondCanvas'></canvas
</body>
</html>
JS:
$(document).ready(function() {
paper.install(window);
paper.setup(document.getElementById('firstCanvas'));
var tool = new Tool();
tool.onMouseDown = function(event) {
var c = Shape.Circle(event.point.x, event.point.y, 20);
c.fillColor = 'green';
};
paper.view.draw();
});
Thank you in advance.
With kind regards,
You could use PaperScope, and activate each scope with scope.activate() then draw in the activated scope.
It's in the paper.js docs here http://paperjs.org/reference/paperscope/

How change color of dotted line in mxgraph

I want to change the color of dotted line from black to red when we drag a vertex
Question: I want to change dotted line color to red from black while drag
Here is how it appears on drag
I tried to find the dashed color on drag in mxConstants but i did not find it
function main(container)
{
// Checks if the browser is supported
if (!mxClient.isBrowserSupported())
{
// Displays an error message if the browser is not supported.
mxUtils.error('Browser is not supported!', 200, false);
}
else
{
// Disables the built-in context menu
mxEvent.disableContextMenu(container);
// Creates the graph inside the given container
var graph = new mxGraph(container);
// Enables rubberband selection
new mxRubberband(graph);
// Gets the default parent for inserting new cells. This
// is normally the first child of the root (ie. layer 0).
var parent = graph.getDefaultParent();
// Adds cells to the model in a single step
graph.getModel().beginUpdate();
try
{
var v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);
}
finally
{
// Updates the display
graph.getModel().endUpdate();
}
}
};
<html>
<head>
<title>Toolbar example for mxGraph</title>
<script type="text/javascript">
mxBasePath = 'https://jgraph.github.io/mxgraph/javascript/src';
</script>
<script src="https://jgraph.github.io/mxgraph/javascript/src/js/mxClient.js"></script>
<script src="./app.js"></script>
</head>
<body onload="main(document.getElementById('graphContainer'))">
<div id="graphContainer">
</div>
</body>
</html>
Please help me thanks in advance!!!
Based on this you can do that by below code:
mxGraphHandler.prototype.previewColor = 'red';
Working snippet:
function main(container)
{
mxGraphHandler.prototype.previewColor = 'red';
// Checks if the browser is supported
if (!mxClient.isBrowserSupported())
{
// Displays an error message if the browser is not supported.
mxUtils.error('Browser is not supported!', 200, false);
}
else
{
// Disables the built-in context menu
mxEvent.disableContextMenu(container);
// Creates the graph inside the given container
var graph = new mxGraph(container);
// Enables rubberband selection
new mxRubberband(graph);
// Gets the default parent for inserting new cells. This
// is normally the first child of the root (ie. layer 0).
var parent = graph.getDefaultParent();
// Adds cells to the model in a single step
graph.getModel().beginUpdate();
try
{
var v1 = graph.insertVertex(parent, null, 'Hello,', 20, 20, 80, 30);
}
finally
{
// Updates the display
graph.getModel().endUpdate();
}
}
};
<html>
<head>
<title>Toolbar example for mxGraph</title>
<script type="text/javascript">
mxBasePath = 'https://jgraph.github.io/mxgraph/javascript/src';
</script>
<script src="https://jgraph.github.io/mxgraph/javascript/src/js/mxClient.js"></script>
<script src="./app.js"></script>
</head>
<body onload="main(document.getElementById('graphContainer'))">
<div id="graphContainer">
</div>
</body>
</html>

Zimjs pressmove event doesn't work outer the elements

I'm using zimjs library for my canvas project. I'm trying to do continued pressing around the circles. When pressing and moving over the circles, circles must be change color. But pressmove event don't start outer the circles. You need to start to press over the circle. if I start pressing over the circle, the other circle is not affected.
Here is zimjs events:
https://zimjs.com/tips.html (See Events)
What do I want approximately?
https://zimjs.com/intro/index.html (See drag to eraser example. I want like this but without eraser. Only single pressing)
Note: I can't use mouse events. They didn't work on phone touchs.
See snippet:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>ZIM Frame - Outside Template</title>
<script src="https://zimjs.org/cdn/1.3.0/createjs.js"></script>
<script src="https://zimjs.org/cdn/10.9.0/zim.js"></script>
<!-- use zimjs.com/distill for minified individual functions! -->
<script>
var scaling = "fit"; // this will resize to fit inside the screen dimensions
var width = 600;
var height = 400;
var color = white; // or any HTML color such as "violet" or "#333333"
var outerColor = light;
var frame = new Frame(scaling, width, height, color, outerColor);
frame.on("ready", function() {
var stage = frame.stage;
var circle1 = new Circle(20, "red").pos(100,40, stage)
var circle2 = new Circle(20, "blue").pos(200,40, stage)
circle1.on("pressmove", () => {
circle1.color = "green"
stage.update()
console.log("Circle - 1 || Circles pressmove doesn't work when pressing start the outside")
})
circle2.on("pressmove", () => {
circle2.color = "green"
stage.update()
console.log("Circle - 2 || Circles pressmove doesn't work when pressing start the outside")
})
var button = new Button(140, 100, "reset", grey, dark).center(stage).tap(() => {
circle1.color = "red"
circle2.color = "blue"
stage.update()
})
new Label("Pressmove can be start anywhere", 16).pos(0, 300)
new Label("When pressing and moving over the circles,", 16).pos(0, 320)
new Label("circles must be select and change color,", 16).pos(0, 340)
stage.on("pressmove", () => console.log("Stage !!. Stage pressmove doesn't work when pressing outside the circles"))
stage.update();
}); // end of ready
</script>
<meta name="viewport" content="width=device-width, user-scalable=no" />
</head>
<body>
</body>
</html>
It is true that the pressmove event only works as you press on an object and move. If you want to start the press off the object or indeed anywhere then you use stage.on("stagemousedown", function); Mouse events DO work on mobile they are triggered by a touch so you do not even have to think of it. There is also "stagemousemove" and "stagemouseup". Objects on the stage get "mousedown", "presssmove", "pressup", "mouseover", "mouseout", etc. Usually we would change color on "mouseover" and change back on "mouseout" - ZIM has hov() that will do that. Or a Button() and Label() have built in backgroundColor and rollBackgroundColor.
If you really need to press anywhere before activating a change of color you could do something like this to remember the mousedown stage in general:
let mousedown = false;
stage.on("stagemousedown", ()=>{mousedown=true});
stage.on("stagemouseup", ()=>{mousedown=false});
const circle = new Circle().center();
circle.on("mouseover", ()=>{
if (mousedown) {
circle.color = red;
stage.update();
}
});
Or you could specifically add a stagemousemove event inside a stagemousedown event and remove it in a stagemouseup event to get the equivalent to a stage pressmove event. The pressmove event was created to help with dragging objects and usually, we do not drag the stage.
Hope this helps and apologies for the delay - you are welcome to join us at https://zimjs.com/slack for discussion! Cheers.

Canvas Clear in Paper.js

Does anyone know the best way to clear a canvas using paper.js
I tried the regular canvas clearing methods but they do not seem to work with paper.js
Html
<canvas id="myCanvas" style="background:url(images/graphpaper.jpg); background-repeat:no-repeat" height="400px" width="400px;"></canvas>
<button class="btn btn-default button" id="clearcanvas" onClick="clearcanvas();" type="button">Clear</button>
Javascript/Paperscript
<script type="text/paperscript" canvas="myCanvas">
// Create a Paper.js Path to draw a line into it:
tool.minDistance = 5;
var path;
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
function onMouseDown(event) {
// Create a new path and give it a stroke color:
path = new Path();
path.strokeColor = 'red';
path.strokeWidth= 3;
path.opacity="0.4";
// Add a segment to the path where
// you clicked:
path.add(event.point, event.point);
}
function onMouseDrag(event) {
// Every drag event, add a segment
// to the path at the position of the mouse:
path.add(event.point, event.point);
}
</script>
Regular clearing does not work because paper.js maintains a scene graph and takes care of drawing it for you. If you want to clear all items that you have created in a project, you need to delete the actual items:
project.activeLayer.removeChildren(); works as long as all your items are inside one layer. There is also project.clear() which removes everything, including the layer.
In case someone comes looking for an answer with little experience in Javascript, I made a simple example :
1) As Jürg Lehni mentioned project.activeLayer.removeChildren(); can be used to remove all items inside active layer.
2) To reflect the cleaning you have to call paper.view.draw();.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Circles</title>
<link rel="stylesheet" href="style.css">
<script type="text/javascript" src="paper-full.js"></script>
<script type="text/paperscript" canvas="canvas">
function onMouseUp(event) {
var circle = new Path.Circle({
center: event.middlePoint,
radius: event.delta.length / 2
});
circle.strokeColor = 'black';
circle.fillColor = 'white';
}
</script>
<script type="text/javascript">
paper.install(window);
window.onload = function () {
paper.setup('canvas');
document.getElementById('reset').onclick = function(){
paper.project.activeLayer.removeChildren();
paper.view.draw();
}
};
</script>
</head>
<body>
<canvas style="background-color: #eeeeed" id="canvas" resize></canvas>
<input id="reset" type="button" value="Reset"/>
</body>
</html>
CSS :
html,
body {
margin: 0;
overflow: hidden;
height: 100%;
}
/* Scale canvas with resize attribute to full size */
canvas[resize] {
width: 58%;
height: 100%;
}
you can use project.activeLayer.removeChildren(); for clear entire layer,
or you can add your new paths to group and remove all childrens in group
var myPath;
var group = new Group();
function onMouseDown(event) {
myPath = new Path();
}
function onMouseDrag(event) {
myPath.add(event.point);
}
function onMouseUp(event) {
var myCircle = new Path.Circle({
center: event.point,
radius: 10
});
myCircle.strokeColor = 'black';
myCircle.fillColor = 'red';
group.addChild(myCircle);
}
// connect your undo function and button
document.getElementById('clearbutton').onclick = btnClear;
function btnClear(){
group.removeChildren();
}
c.width = c.width; ctx.clearRect(0,0,c.width,c.height); should be a good catchall if you've not tried it.
Beware however - setting canvas width will reset the canvas state including any applied transforms.
A quick google took me to https://groups.google.com/forum/#!topic/paperjs/orL7YwBdZq4 which specifies another (more paper.js specific) solution:
project.activeLayer.removeChildren();

FabricJS - add line to canvas and control only it's length

I am using FabricJS to develop a simple floor plan editor. When adding a Line (that should be a wall) to the canvas, I want the ability to control only the length of the line, not it's width-height.
I have tried setting lockScalingY: true but the problem is that when adding a line the control handles are so close to each other that I can't interact only with the horizontal control handles... the corner handles actually block the horizontal handles...
How can this be done?
Fine control of adjoining FabricJS lines
The way graphics programs like photoshop deal with this common problem is to let the user position lines near the desired intersection and then use the arrowkeys to "nudge" the line into place pixel one at a time.
The code below illustrates a rough solution that does the same thing for FabricJS lines:
User selects a line.
Turn off the control handles and borders.
Let the user "nudge" the line into perfect alignment (here the line length is increased).
Turn the the control handles and borders back On.
This is just "proof of concept" code. In your production app:
You'll probably want to use arrowkeys instead of buttons to "nudge".
I made nudging go 10px at a time--you might do this 1px at a time.
And when the user starts nudging, you'll automatically turn off the handles and borders for them.
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/dd742/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<script type="text/javascript" src="fabric.min.js"></script>
<style>
body{ background-color: ivory; padding:30px; }
canvas{border: 1px solid red; }
</style>
<script>
$(function(){
var canvas = new fabric.Canvas('canvas');
var selectedLine;
var line1=newLine(50,100,150,100,"red");
var line2=newLine(160,50,160,150,"green");
canvas.add(line1,line2);
function newLine(x1,y1,x2,y2,color){
var line=new fabric.Line(
[x1,y1,x2,y2],
{fill:color,strokeWidth:15,selectable:true}
);
return(line);
};
$("#hOff").click(function(){
selectedLine.hasBorders=false;
selectedLine.hasControls=false;
canvas.renderAll();
});
$("#hOn").click(function(){
selectedLine.hasBorders=false;
selectedLine.hasControls=true;
canvas.renderAll();
});
$("#shorter").click(function(){
changeLineLength(selectedLine,-10);
canvas.renderAll();
});
$("#longer").click(function(){
changeLineLength(selectedLine,10);
canvas.renderAll();
});
function changeLineLength(line,adjustment){
if(!selectedLine){return;}
if(line.get("y1")==line.get("y2")){ // line is horizontal
line.set("x2",line.get("x2")+adjustment);
}else
if(line.get("x1")==line.get("x2")){ // line is vertical
line.set("y2",line.get("y2")+adjustment);
}else{ // line is diagonal
line.set("x2",line.get("x2")+adjustment);
line.set("y2",line.get("y2")+adjustment);
}
}
canvas.observe('object:selected', function(eventTarget) {
var event=eventTarget.e;
var target=eventTarget.target;
selectedLine=target;
});
}); // end $(function(){});
</script>
</head>
<body>
<p>Select a line,</p><br/>
<p>Turn handles Off</p><br/>
<p>Make lines intersect by pressing longer/shorter</p><br/>
<canvas id="canvas" width="600" height="200"></canvas>
<button id="hOff">Handles Off</button>
<button id="shorter">Shorter</button>
<button id="longer">Longer</button><br/>
<button id="hOn">Handles On</button>
</body>
</html>
May be helps somebody.
Add handler to event
'object:selected': _objSelected
Then at handler set unneeded control to false.
function _objSelected(e)
{
if(e.target.objectType == 'line')
{
var cv = e.target._controlsVisibility;
// mt - middle top, tl - top left and etc.
cv.mt = cv.mb = cv.tl = cv.bl = cv.tr = cv.br = false;
}
}
Also I added objectType (custom property) and padding (for beauty) to new object Line
var obj = new fabric.Line([50, 50, 150, 50], { padding: 10, objectType: 'line' });

Categories

Resources