Due demand, I give all the code in respect to onmouseClick:
First I import svg each in a new layer into canvas:
//imports svg from external js script
var svgimportSVG = function (elem,x) {
// creates a new layer for each imported svg
var layer = new Layer();
layer.name = "Layer" +x;
layer.activate();
// import here
rect = paper.project.importSVG(elem,function(item){
console.log("Elem: " + elem);
});
Then I build the "frame" as a path on bounds:
// build a frame
rect.data.showBounds = new Path.Rectangle({
rectangle: rect.bounds,
strokeColor: 'aqua'
});
return rect;
}
I want the effect that only the clicked element or the least imported element has a visible frame:
tool.onMouseDown = function(e) {
var hitResult = project.hitTest(e.point, hitOptions);
if(hitResult){
var SVGGroup = searchSVGGroup(hitResult.item,"svg");
var SVGLayer = searchSVGGroup(hitResult.item,"layer");
// Layer of clicked object shall be in front or last element in project.layers
console.log(SVGLayer.name);
var IndexOfLayer = project.layers.indexOf(SVGLayer);
project.layers.splice(IndexOfLayer,1);
project.layers.push(SVGLayer);
var LayersLengthnew = project.layers.length;
//Clicked object can be influenced ouside paperscope
window.globals.extExportOnMouseClick(project.layers[LayersLengthnew -1].name);
SVGGroup.data.showBounds = new Path.Rectangle({
rectangle: rect.bounds,
strokeColor: 'aqua'
});
// sent as old clicked object
svgSetRemoveFrameofGroup(SVGGroup);
}
else{...}
}
//create an empty object that holds the last clicked object
var svgFramedGroup = {};
var svgSetRemoveFrameofGroup = function(rect){
var rectold = {};
console.log("rect name: "+ rect.name); // gives correct name
if(svgFramedGroup.data){
rectold = svgFramedGroup;
console.log("rect old name: "+ rectold.name); // gives correct name
}
svgFramedGroup = rect;
if(!svg_isEmpty(rectold)){
//... showBounds should go to Garbage collector
rectold = rectold.data.showBounds.remove();
}
return rectold;
}
But the further clicked element has still its bounds which is a path!?
I answered you here for the same question.
The only different thing is that here you're asking for a "frame" shown when an element is clicked and there you're asking for it to be hidden when element is clicked (which is what I did in my example).
But you should be able to get the logic anyway.
Related
I'm working with svg through Raphael.js and I need to collapse SVG group and show it on click.
I've tried to use 'visibility' attriburte of SVG group and change it on click, but it is ok with hiding but it's not appear back;
const GroupCollapse = function(paper) {
const $svg = paper.canvas; // #mysvg is SVG doc
const g = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
$svg.appendChild(g);
this.paper = paper;
this.node = g;
this.attrs = {};
this._ = {};
this.add = function (el) {
g.appendChild(el.node);
};
};
GroupCollapse.prototype = Raphael.el;
Raphael.fn.groupCollapse = function(... args) {
return new GroupCollapse(this, ... args)
};
This is my realisation of custom group.
Then I create it like this:
let gc = paper.groupCollapse();
I make it 'hidden' And I have a function to make it visible that didn't work.
function showCollapsed() {
gc.visibility = "visible";
}
I want to have SVG group of Raphael circles that collapsing to one circle and unfolds on click to this circle. Could you help me and show the best way to do that. Thank you!
I have two canvas the first one is working good, but when I initialize the second one the paper.Tool does not work properly, sometimes the event onMouseMove works others not.
var dataLoad;
var mypapers = []
$(document).ready(function () {
dataLoad = new DataLoad();
mypapers[0] = new paper.PaperScope();
mypapers[1] = new paper.PaperScope();
mypapers[0].setup(document.getElementById('dataCanvas'));
dataLoad.Init();
});
// "returnedData" THIS ARRAY COMES FROM AN AJAX CALL
DataLoad.prototype = {
Init: function () {
var self = this;
var paperData = new
DataReader(document.getElementById('dataCanvas'));
paperData.Init(returnedData[i],mypapers[0]);
paperData.Draw(true);
self.datas.push(paperData);
}
});
Till here everything is good the first canvas is populated with the graphics I setted.
DataReader.prototype = {
Init: function (data,mypaper) {
var self = this;
paper = mypaper;
self.paper = paper;
self.toolPan = new self.paper.Tool()
self.toolPan.activate();
self.toolPan.onMouseDrag = function (event) {
var delta = event.downPoint.subtract(event.point)
self.paper.view.scrollBy(delta)
};
self.toolPan.onMouseMove = function (event) {
self.OnMouseMove(event);
};
self.toolPan.onMouseUp = function (event) {
// AFTER MAKE A SELECTION OF ITEMS IN THE CANVAS CALLING THE SECOND CANVAS
var core = self.HighlightElementsInBox();
self.dc = new DefineComponent();
self.dc.Init(core);
$('#DCCanvas').modal('toggle'); // THE CANVAS IS INSIDE THIS BOOTSTRAP MODAL
}
}
});
/* this initialize the second canvas that basically creates another instance of the same prototype i use to manipulate paperjs in the first canvas */
DefineComponent.prototype = {
Init: function (dataCore) {
var self = this;
mypapers[1].setup(document.getElementById('DCCanvas')); // setting second canvas
var paperDataDC = new DataReader(document.getElementById('DCCanvas'));
paperDataDC.Init(dataCore,mypapers[1]);
paperDataDC.Draw(true);
self.datas.push(paperDatasDC);
}
});
In this second canvas all is drawn correctly, but the events onmousedrag and onmousemove does not works properly the first one move the canvas in another position where the mouse is not and mousemove works only in some places of the canvas not in all.
As you are creating two different paperScopes you will need to toggle between them when working with one or the other.
You are saving both paperScopes inside "mypapers" array
mypapers[0] = new paper.PaperScope();
mypapers[1] = new paper.PaperScope();
So to use any of those you should do
mypapers[0].activate();
// or
mypapers[1].activate();
Check out this (min setup) example of what I mean above.
Also, follow stefan's suggestion if you want more help on this since it's hard for people to try to help without a minimal working example
I am creating a Mind Mapping software using raphael.js and javascript.
I want to create a set of nodes where a node is like a rectangle and has its attributes as id, x,y coordinates etc. There is a plus icon on the rectangle on click of which a new node/rectangle is created with its new unique id. I want to create node and assign each created node its id in an Object Oriented fashion.
I am having difficulty in assigning a unique id to each node on its creation. I want to set ids starting from 0,1,2,3...
Second difficulty is selecting a node. I want to select a node based on its id.
Please have a look at the following code.
Could someone please help me in assigning ids to each of the nodes and to select each node based on its id?
assume that there is a canvas of 1000px width and 700px height.
paper = Raphael("canvas", 1000,700);
// create.js
drawNode(290, 80);
function drawNode(x,y)
{
id=0;
a = new node(x,y,id);
a.drawNode();
}
// nodes.js
var node = function(x,y,id){
this.id=id;
this.x=x;
this.y=y;
this.drawNode = function(){
var st = paper.set();
a = paper.rect(this.x,this.y, 100, 40, 2);
a.add = paper.image('images/plus.png', this.x+77, this.y+12, 20, 20)
a.attr({fill: '#8EDFF0', stroke: '#6AB0F2'});
st.push(a,a.text,a.add,a.addnote);
a.add.click(this.add);
}
this.add = function () {
id=1;
a = new node(this.attrs.x+150, this.attrs.y,id);
a.drawNode();
}
}
Please tell me how can I set unique id to each node instead of hardcoding the values and how to do that.
You, probably, need some NodeCostructor singleton with id parameter set to 0 from the start and createNode as function that accepts x and y, uses NodeCostructor's id to draw a node and returns you a node, than increases NodeCostructor's id value. A basic example of how should it be (EDIT: I've found some js singleton tutorial, so this new code will be more valid in terms of OOP):
var NodeConstructor = (function() {
var instance = null;
function NCInstanceCreate() {
var id=0;
createNode = function(x,y) {
tmp = new node(x, y, this.id);
this.id++;
return tmp;
}
return {
createNode : createNode,
id : id
}
}
function getInstance() {
if( ! instance ) {
instance = new NCInstanceCreate();
}
return instance;
}
return {
getInstance : getInstance
};
})(window);
var node = function(x,y,id){
this.id=id;
this.x=x;
this.y=y;
}
myConstructor=NodeConstructor.getInstance();
console.log(myConstructor.createNode(100,200));
console.log(myConstructor.createNode(110,220));
console.log(myConstructor.createNode(130,240));
console.log(myConstructor.id);
So you basically should use myConstructor.createNode(x,y) instead of new node(x,y,id) whenever you want to create node.
I'm taking an adventure into the depths of JavaScript and have come across a little problem that I can't get my head around.
Everything I know about programming is self taught, this problem might have some terminology behind it I have never heard of, so I don't know what it would be called.
I'll explain the problem I am experiencing.
I've been writing a framework for HTML5 canvas for displaying 2d and 3d graphics.
As you might expect, I have designed an element class, these elements have positions on the canvas which are built from a vector class I put together.
The problem I'm having is, if I make two "Text" objects, then call a function inside their position object, all the positions of the "Text" objects change to this value:
var usernameLabel = new C.Text('Username:');
usernameLabel.position.set(30,30)
var username = new C.Text('Hello World');
username.position.set(0,70)
console.log(usernameLabel.position.x) // 0 when it should be 30
I'm sure there is something I missed, I just can't figure out what.
C.Text.prototype = new C.Element();
C.Element.position = new JC.Vector();
Any help would be most appreciated!
This is my full Element class
C.elements = 0;
C.Element = function()
{
this.id = C.elements ++;
this.position = new C.Vector();
this.rotation = new C.Vector();
this.style = new C.Style();
this.children = [];
}
C.Element.prototype = {
constructor : C.Element,
addChildObject : function( o )
{
return this.children.push(o);
},
removeChildObject : function( o )
{
this.children.splice(o,1);
}
}
Text class
C.Text = function(string)
{
this.string = string || '';
}
C.Text.prototype = new C.Element();
C.Text.prototype.constructor = C.Text();
I also have more classes built from C.Element obviously, for example:
C.Rectangle = function(width, height)
{
this.style.setSize(width,height);
}
C.Rectangle.prototype = new C.Element();
C.Rectangle.prototype.constructor = new C.Rectangle();
var usernameLabel = new C.Text('Username:');
usernameLabel.position.set(30,30) // 0,70?
var username = new C.Text('');
username.position.set(0,70) // 0,70
var rect = new C.Rectangle(20,0);
rect.position.set(30,80) // 90,80?
var rect2 = new C.Rectangle(20,0);
rect2.position.set(90,80) // 90,80
From the looks of it, you are declaring position as a 'static' variable on the object, which means it will change. To make it change only on a specific object you need one of the following:
C.Element.prototype.position = new JC.Vector();
or inside a function within the object
this.position = new JC.Vector();
These declarations are for items that are specific to the object, where as the C.Element.position declaration is for something that will be the same in all instances of the object.
Update
Instead of declaring C.Text.prototype = new C.Element(). Try using C.Text.prototype = C.Element.prototype. Hopefully that will fix your problem. Instead of creating a new object to base it on, it bases it directly on the prototype of C.Element
I found the answer! Thanks for the help! The solution was to make the parent object do a call
for a reason I don't fully understand.
C.Text = function(string)
{
C.Object.call(this)
this.string = string || '';
return this;
}
C.Text.prototype = new C.Object();
C.Text.prototype.constructor = C.Text;
Here I've tried to create a simple drawing area widget containing a single circle, using google closure.
I load it by calling sketcher.load() within html script tag and get an error:
Uncaught TypeError: Cannot set property 'Widget' of undefined - what is not right here?
goog.provide('sketcher');
goog.require('goog.dom');
goog.require('goog.graphics');
goog.require('goog.ui.Component');
var sketcher = {};
sketcher.prototype.Widget = function(el){
goog.ui.Component.call(this);
this.parent_ = goog.dom.getElement(el);
this.g_ = new goog.graphics.createGraphics(600, 400);
this.appendChild(this.g_);$
var fill = new goog.graphics.SolidFill('yellow');
var stroke = new goog.graphics.Stroke(1,'black');
circle = this.g_.drawCircle(300, 200, 50, stroke, fill);
this.g_.render(this._parent);
};
goog.inherits(sketcher.Widget, goog.ui.Component);
sketcher.prototype.load = function(){
var canvas = goog.dom.createDom('div', {'id':'canvas'});
goog.dom.appendChild(document.body, canvas);
var widget = new sketcher.Widget(canvas);
};
First problem: sketcher is a namespace, because you goog.provide it. You don't need to declare it again.
Second problem: sketcher.Widget should be thus, not sketcher.prototype.Widget. Only functions have prototypes; you should go back and review how objects work in JavaScript unless that was just a typo. It should look like this.
goog.provide('sketcher');
goog.require('goog.dom');
goog.require('goog.graphics');
goog.require('goog.ui.Component');
/**
* My sketcher widget.
* #param {Element} e1
* #constructor
*/
sketcher.Widget = function(el){
goog.ui.Component.call(this);
this.parent_ = goog.dom.getElement(el);
this.g_ = new goog.graphics.createGraphics(600, 400);
this.appendChild(this.g_);$
var fill = new goog.graphics.SolidFill('yellow');
var stroke = new goog.graphics.Stroke(1,'black');
circle = this.g_.drawCircle(300, 200, 50, stroke, fill);
this.g_.render(this._parent);
};
goog.inherits(sketcher.Widget, goog.ui.Component);
sketcher.prototype.load = function(){
var canvas = goog.dom.createDom('div', {'id':'canvas'});
goog.dom.appendChild(document.body, canvas);
var widget = new sketcher.Widget(canvas);
};
here is a link to a simple svg drawing widget built with closure
http://webos-goodies.googlecode.com/svn/trunk/blog/articles/make_a_drawing_tool_with_closure_library/simple-draw.js