How to append an element inside another on snapsvg? - javascript

I'm building a domino piece using Snapsvg http://snapsvg.io/
Here is the code so far.
var s = Snap(800,600);
// elem structure
var elem = s.rect(10,10,100,200);
var s1 = s.rect(0,0,90,90);
elem.attr({
fill: '#fff',
stroke: '#000',
strokeWidth: 2
});
s1.attr({
fill: '#bada55'
});
s1.append(elem)
I built the piece structure var elem that is width:100 and height:200 and I built an square var s1 width:90 height:90. I'm trying to append s1 inside elem. When i use s1.append(elem), the elem disappears, what am I doing wrong?

In SVG graphical elements i.e. rect, polygon etc are not nestable.
There are containers (Paper.group) which can contain graphical elements which you can add transforms to to move multiple elements at once if you want. You could create one of those and put both your rect elements within it as siblings.

Related

Snap.svg and dynamic text

I'm trying to place text dynamically into an svg created by Snap, this is what I tried:
this.setContent(
`<svg id="${this.svgId}"></svg>`
);
var snap = Snap($(`#${this.svgId}`)[0]);
text = "asdfsdfsdsfd";
var rect = snap.paper.rect(0, 0, 50, text.length*3 + 4, 10);
snap.text(1.5,10, text);
console.log("rect", rect);
console.log("snap", snap);
rect.attr({
fill: "#FFFFFF",
fillOpacity: 0.6,
});
I get this:
I want the rectangle to be just a little bigger than the text, but there must be a better way to do it than to calculate the length and height of the text, and that's assuming the font size won't change.
This is the only result I found regarding text in the snap docs: http://snapsvg.io/docs/#Paper.text
You could try using getBBox() on the text element, and use that to figure the size of the rect. getBBox() wll give you the x,y,width,height,x2,y2 figures to help.
var text = s.text(0,0,'blah blah')
var bb = text.getBBox();
var rect = s.rect(bb.x, bb.y, bb.width, bb.height )
Adjusting with offsets for whatever padding etc that you want. You may also need to allow for stroke widths, as I don't think that's included.

Click through path in Raphael

I have defined a path with opacity 0 that includes within several elements. The purpose of that is because when mouse is over that path, the element appears (or disappear if we left the path). My problem is since the path is on top of the canvas, I cannot click on those elements and expect to be able to handle the event.
What would be the best strategy to deal with that?
I tried to put the path on back(); but when I hover over an element, it's like if I left the path.
I tried to put the element on top, but same result as before.
Using the function ispointinsidepath() and then getting the coordinates of the point I clicked seems fastidious, since element size are not constant.
You can put handlers on each of the elements, and deal with it that way. Might even be slightly easier if using Snap rather than Raphael as you can use groups then (and not need multiple event handlers), but assuming Raphael is a requirement you could do this...
var r = paper.rect(50,50,200,200).attr({ fill: 'blue', opacity: '0'}).hover( hoverover, hoverout )
var c1 = paper.circle(100,100,30).attr({ fill: 'red' }).click( clickFunc ).hover( hoverover, hoverout)
var c2 = paper.circle(200,200,30).attr({ fill: 'blue' }).click( clickFunc ).hover( hoverover, hoverout )
function hoverover() { r.attr({ opacity: 1 } ) }
function hoverout() { r.attr({ opacity: 0 } ) }
function clickFunc() { alert('clicked')}
jsfiddle

Generating onclick text at the bottom of my SVG, modifying 'selected' colour

With the aid of a tutorial, I've built a map of five regions of England in SVG. I've used Raphael to work with it a little. Most of it seems to be turning out alright so far:
http://codepen.io/msummers40/pen/EjExeO
I'm trying to add two more features and am just not sure how to do it. Are you able to help, please?
I'd like to: Set up the effect of the regions turning red upon clicking so that only the most recently clicked region is coloured. Can you help explain what I'm supposed to do to make this shift from region to region? At the moment, a region gets clicked and stays highlighted.
I'd like to figure out how to add more text to the bottom of the canvas. It may mean adding more information to my JSON but I'm hoping that I can add the text - about two paragraphs with a hyperlink - as a string.
Can you please let me know if you have thoughts about ways that I can do the two things outlined above?
Thank you,
Matt
The full code is on Codepen. What I've added below is a representative sample of the code.
var regions = [
{'title':"northeast_england", 'path' : "M219.02,6.876l-0.079,0.05l-0.482,0.371L218.23,7.47l-0.858,0.346h-0.008l-0.307,0.26l-0.779,0.666 l-0.104,0.278l-0.005,0.019l0.056,0.481l0.116,0.846l0.048,0.395l-0.344,1.05l-0.052-0.007v0.007l-0.635-0.081l-0.375,0.167 l-0.148,0.061v0.006l-0.1,0.328l0.178,0.338l-0.104,0.353h-0.006l-0.32,0.179l-0.056,0.031l-0.161,0.729h-0.006v0.012l-0.271,0.117 l-0.08,0.031l-0.031-0.019l-0.043,0.019l-0.327-0.167l-0.147-0.079l-0.117-0.007h-0.021l-0.216-0.006l-0.419,0.252l-0.009,0.007 l-0.004,0.302v0.605l-0.117,0.292l-0.037,0.11h-0.006v0.006h-0.025l-0.37,0.056l-0.536,0.079l-0.562,0.372l0.017,0.165l0.033,0.187 l0.481,0.788l0.023,0.038l0.008,0.013l-0.988,0.425l-0.594,0.637l-0.011,0.03l-0.187,0.637l-0.068,0.062l-0.801,0.747l-0.409,0.617 l0.062,0.414l0.068,0.414l-0.012,0.012l-0.203,0.228h-0.008l-0.123,0.05l-0.006,0.005l-0.377,0.136l-0.073,0.074l-0.13,0.143 l-0.401,0.426l-0.081,0.08l-0.055,0.055l-0.116,0.136l-0.05,0.364l0.646,0.191l0.025,0.119l0.05,0.153l-0.265,0.148l-0.26,0.155 l-0.155-0.006l-0.005,0.006l-0.309-0.006l-0.648-0.365l-0.624,0.142l-0.363,0.087l-......LOTS MORE COORDINATES...."},
THERE ARE SEVERAL OTHER SVG REGIONS/SHAPES IN THE CODEPEN LINK
var MAP_WIDTH = 600;
var MAP_HEIGHT = 600;
var mapContainer = document.getElementById("map");
var map = new Raphael(mapContainer, MAP_WIDTH, MAP_HEIGHT);
var group = map.set();
var style = {
fill: "#ddd",
stroke: "#aaa",
"stroke-width": 1,
"stroke-linejoin": "round",
cursor: "pointer"
};
regions.forEach(function(region){
group.push(
map.path(region.path).attr('title', region.title)
);
});
group.attr(style);
group.click(function(){
var slug = this.attr('title');
var title;
var fill = this.attr('fill') == 'red' ? '#1f1f1f' : 'red';
// format the title
title = slug.split('-')
.map(function(subString){
return subString[0].toUpperCase() + subString.substr(1);
})
.join(' ')
.trim();
// add some color
this.attr('fill', fill);
// do something useful
document.getElementById('title').textContent = title;
});
For the highlight thing, what I would do is have your click function as follows (pseudocode)::
on-region-clicked {
remove class "highlight" from all regions
add class "highlight" to clicked region
}
Where class "highlight" is:
.highlight {
fill: red;
}
I'll leave the actual Raphael code up to you.

Putting HTML code on JointJS link

I have worked with JointJS now for a while, managing to create elements with HTML in them.
However, I am stuck with another problem, is it possible to place HTML code, like
href, img etc, on a JointJS link and how do I do this?
For example, if I have this link, how do I modify it to contain HTML:
var link = new joint.dia.Link({
source: { id: sourceId },
target: { id: targetId },
attrs: {
'.connection': { 'stroke-width': 3, stroke: '#000000' }
}
});
Thank you!
JointJS doesn't have a direct support for HTML in links. However, it is possible to do with a little bit of JointJS trickery:
// Update position of our HTML whenever source/target or vertices of our link change:
link.on('change:source change:target change:vertices', function() { updateHTMLPosition(link, $html) });
// Update position of our HTML whenever a position of an element in the graph changes:
graph.on('change:position', function() { updateHTMLPosition(link, $html) });
var $html = $('<ul><li>one</li><li>two</li></ul>');
$html.css({ position: 'absolute' }).appendTo(paper.el);
// Function for updating position of our HTML list.
function updateHTMLPosition(link, $html) {
var linkView = paper.findViewByModel(link);
var connectionEl = linkView.$('.connection')[0];
var connectionLength = connectionEl.getTotalLength();
// Position our HTML to the middle of the link.
var position = connectionEl.getPointAtLength(connectionLength/2);
$html.css({ left: position.x, top: position.y });
}
Bit of an old question, but thought I'd add some more ideas. You can add extra svg markup to the label in a link if you like by extending the link object and then setting attributes where needed. For example:
joint.shapes.custom.Link = joint.dia.Link.extend({
labelMarkup: '<g class="label"><rect /><text /></g>'
});
This code overrides the markup for the label, so you can add extra elements in there. You can also update attributes on these elements by:
link.attr('text/text', "new text");
However hyperlinks won't work (at least I haven't got them working in Chrome) and I believe this is because Jointjs listens for all events in the model. So what you should do is use inbuilt events in Jointjs to listen for connection clicks:
paper.on('cell:pointerclick', function(cellView, evt, x, y){
console.log(cellView);
});

In raphaeljs, is there a way to place text within an object to keep rollover state

In creating a svg map using raphael js where I have hover states. How ever I am trying to write the country names onto the map. The problem I am facing is the names become their own object and block the country so I loose hover and click when the cursor is directly over the text. Is there a way where I can draw the text and not have it block the map. I've tried set() but with no sucess.
Thanks,
What I have below doesn't have the text() or print() included:
var r = Raphael('map', 1450, 2180);
arr = new Array();
for (var country in paths) {
var obj = r.path(paths[country].path);
countryName = paths[country].name;
color = paths[country].color;
scolor = paths[country].stroke;
obj.attr({fill:color,stroke:scolor,
'stroke-width': 1,
'stroke-linejoin': 'round'});
arr[obj.id] = country;
obj
.hover(function(){
console.log(arr[this.id]);
this.animate({
fill: paths[arr[this.id]].hover
}, 300);
}, function(){
this.animate({
fill: paths[arr[this.id]].color
}, 300);
})
});
Try setting the pointer-events attribute to none for the text elements.
Documentation:
http://www.w3.org/TR/SVG/interact.html#PointerEventsProperty

Categories