Raphael - rotate whole set not each object - svg

Hi guys i'm trying to rotate few objects at once with Set using Element.animate() but it rotates each element not the whole set and i need whole set
Help me please i'm very new to raphael just about few hours of reading docs and trying functions
var archtype = Raphael("canvas", 600, 600);
archtype.customAttributes.arc = function (xloc, yloc, value, total, R) {
var alpha = 360 / total * value,
a = (90 - alpha) * Math.PI / 180,
x = xloc + R * Math.cos(a),
y = yloc - R * Math.sin(a),
path;
if (total == value) {
path = [["M", xloc, yloc - R],["A", R, R, 0, 1, 1, xloc - 0.01, yloc - R]];
} else {
path = [["M", xloc, yloc - R],["A", R, R, 0, +(alpha > 180), 1, x, y]];
}
return {
path: path
};
};
var circleSet=archtype.set();
var arc_red0 = archtype.path().attr({
"stroke": "#f00",
"stroke-width": 30,
arc: [300, 300, 30, 360, 250]
});
circleSet.push(arc_red0);
var arc_red1 = archtype.path().attr({
"stroke": "#f00",
"stroke-width": 30,
arc: [300, 300, 20, 360, 250],
"transform": "r50,300,300"
});
circleSet.push(arc_red1);
var arc_red2 = archtype.path().attr({
"stroke": "#f00",
"stroke-width": 30,
arc: [300, 300, 80, 360, 250],
"transform": "r90,300,300"
});
circleSet.push(arc_red2);
var arc_red3 = archtype.path().attr({
"stroke": "#f00",
"stroke-width": 30,
arc: [300, 300, 60, 360, 250],
"transform": "r190,300,300"
});
circleSet.push(arc_red3);
var arc_red4 = archtype.path().attr({
"stroke": "#f00",
"stroke-width": 30,
arc: [300, 300, 70, 360, 250],
"transform": "r270,300,300"
});
circleSet.push(arc_red4);
var $angle=0;
(function (){
circleSet.animate({transform:"r"+$angle+",300,300"},200);
$angle++;
init = false;
setTimeout(arguments.callee, 60);
})();

Option 1: Use Raphael's sets feature -- Add all the elements to a set, and then tell Raphael to rotate the set. See http://raphaeljs.com/reference.html#Paper.set for more info.
This won't actually rotate the whole Raphael element, but if all elements of the image are part of the set, it will look like it is doing so.
Option 2: Use standard CSS to rotate the element or it's HTML container. This might actually be the simplest option, but has the down-side that it won't work in older browsers (particularly old versions of IE). There are work-arounds for this (eg CSS Sandpaper), but if you're already using Raphael to aid IE compatibility you may not want to have to use another script as well.

Related

SwiftUI - Setting maxHeight does nothing for Text() inside LazyVGrid()

I'm trying to make some buttons in a LazyVGrid, but for some reason when I do this, maxHeight has no effect:
LazyVGrid(columns: columns, alignment: .center, spacing: 16) {
ForEach(0...20, id: \.self) { index in
Button(action: {
buttonPressed(char: buttons[index])
}, label: {
Text(buttons[index])
.font(.system(size: 30))
.foregroundColor(Color.white)
.frame(maxWidth: 80, maxHeight: 80)
.background(RoundedRectangle(cornerRadius: 8).fill(getButtonColour(char: buttons[index])))
})
}
}
Here are the definitions to variables used in this snippet:
private let buttons = [buttons' text is here]
private let columns: [GridItem] = Array(repeating: GridItem(.flexible(minimum: 0, maximum: 80), spacing: 16), count: 4)
Outside of a LazyVGrid, .frame(maxWidth: 80, maxHeight: 8) takes effect and makes the element bigger, but for some reason, here it doesn't.
Any help would be welcome! Thank you.
You just need to set the idealHeight to 80 as well.
Text(buttons[index])
.font(.system(size: 30))
.foregroundColor(Color.white)
.frame(maxWidth: 80, idealHeight: 80, maxHeight: 80) // <- Here
.background(RoundedRectangle(cornerRadius: 8).fill(getButtonColour(char: buttons[index]).opacity(Double(index) / Double(buttons.count) + 0.1)))
Result (colors may look different because I don't have all the functions):
Additionally, in the screenshot you can see not all the characters are shown. You should change the range in the ForEach to 0 ..< buttons.count to fix this.

FabricJs- Cloning objects loses custom properties

I have set custom properties on SVG objects and on paths within the SVG objects.
Each object I add to the canvas also gets assigned an 'id' property, as well as some others properties that I use to interact with the objects in the app.
So far, when I clone these objects, I have been able to retain the properties that are on the SVG object by storing them in a session variable prior to cloning, then adding them back after cloning.
My problem is with the properties that are set on each of the object.paths. I have an 'id' property for each path, which I use for some functions that can manipulate the paths within the object.
So for example, before I group the object, the object.paths attribute looks like this...
paths: Array(4)
0: klass {id: "_25mm_x_400mm_ROUND", d: "M400.5,60.5A21.52,21.52", fill: "#ccc", dirty: false, stroke: "#000", …}
1: klass {id: "_25mm_x_400mm_ROUND", d: "M400.5,60.5v25c0", stroke: "#000", dirty: false, strokeMiterLimit: 10, …}
2: {id: "shapeTopColor", d: "M400.5,60.5A21.52,21.52", fill: "rgba(0, 0, 0, 0)", dirty: false, stroke: "#000", …}
3: {id: "shapeSideColor", d: "M400.5,60.5v25c0", stroke: "#000", dirty: false, strokeMiterLimit: 10, …}
Then, after ungrouping the object, the object.paths attribute looks like this...
paths: Array(4)
0: klass {type: "path", originX: "left", originY: "top", left: 0.4999999999999982, top: 0.5, …}
1: klass {type: "path", originX: "left", originY: "top", left: 0.5, top: 60.5, …}
2: klass {type: "path", originX: "left", originY: "top", left: 0.4999999999999982, top: 0.5, …}
3: klass {type: "path", originX: "left", originY: "top", left: 0.5, top: 60.5, …}
This breaks some functions that use the 'shapeTopColor and 'shapeSideColor' ids to change fill attributes for each path. So if a user groups an object, then ungroups it, they are no longer able to change the colour of the object.
Here is the code I am using to group objects...
export function groupSelectedItems() {
canvas = document.getElementById("c").fabric;
var activegroup = canvas.getActiveGroup();
var objectsInGroup = activegroup.getObjects();
var objectIds = [];
activegroup.clone(function(newgroup) {
canvas.discardActiveGroup();
objectsInGroup.forEach(function(object) {
objectIds.push({
'id':object.id,
'componentType':object.componentType,
'shape': object.shape,
// paths = object.paths //Tried this but causes errors.
});
canvas.remove(object);
});
newgroup.setControlsVisibility({'tl': false, 'tr': false, 'bl': false, 'br': false, 'ml': false, 'mr': false, 'mb': false, 'mt': false});
canvas.add(newgroup);
//Store the objects id's on to a session variable.
Session.set('objectIds', objectIds);
//put original objects id's back onto the new groups objects respectively.
var objectsInNewGroup = newgroup.getObjects();
objectsInNewGroup.forEach(function(object, key) {
Session.get('objectIds').forEach(function(o, i) {
if (key == i) {
object.id = o.id
object.componentType = o.componentType,
object.shape = o.shape
// object.paths = o.paths
}
});
});
});
}
So my question is, how can I clone an object or group and not lose any custom attributes I have set?
DEMO
var canvas = new fabric.Canvas('c');
var rect1 = new fabric.Rect({
id: 1,
width: 100,
height: 100,
fill: 'red',
componentType: 'a1',
shape: 'round1'
});
var rect2 = new fabric.Rect({
id: 2,
left:10,
top:20,
width: 100,
height: 100,
fill: 'magenta',
componentType: 'a2',
shape: 'round2'
});
var rect3 = new fabric.Rect({
id: 3,
left:30,
top:30,
width: 100,
height: 100,
fill: 'yellow',
componentType: 'a3',
shape: 'round3'
});
var group = new fabric.Group([rect1, rect2, rect3]);
canvas.add(group)
canvas.setActiveObject(group);
function cloneObj() {
group.clone(function(newgroup) {
canvas.add(newgroup.set({
left: newgroup.left + 10,
top: newgroup.top + 10
}));
console.log(newgroup);
}, ['id', 'componentType', 'shape']);
}
canvas {
border: 1px solid #999;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<button onclick='cloneObj()'>Clone</button>
<canvas id="c" width="700" height="400"></canvas>
clone accepts a callback and array for additional property to include in cloned object.
Use this code to save and get custom properties at initialization of component
fabric.Object.prototype.toObject = (function (toObject) {
return function (propertiesToInclude) {
propertiesToInclude = (propertiesToInclude || []).concat(
["data", "name", "lockRotation"] // custom attributes
);
return toObject.apply(this, [propertiesToInclude]);
};
})(fabric.Object.prototype.toObject);

Changing Port Location in custom element in JointJS

I was able to create a custom element utilizing answers from this question:
Using predefined SVG file for creating a custom JointJS shape with ports
After reviewing the tutorials for JointJS I don't see how to move the ports to different locations on the element.
Thanks
Example code:
http://jsfiddle.net/jshubert/9a8brrun/
var el1 = new joint.shapes.devs.Model({
markup: '<g class="rotatable"><g class="scalable"><image class="body"/></g><text class="label"/><g class="inPorts"/><g class="outPorts"/></g>',
size: {
width: 100,
height: 100
},
position: {
x: 50,
y: 75
},
attrs: {
'.label': { text: 'SW_1', 'ref-x': .1, 'ref-y': .01},
'.body': {
width: 1024,
height: 768,
'xlink:href': 'data:image/svg+xml;utf8,' + encodeURIComponent(svgFile),
preserveAspectRatio: 'none'
}
},
inPorts: ['1'],
outPorts: ['2']
});
ref-x, ref-y applied on appropriate selector can do the trick eg.
'.inPorts .port0 .port-body' : {'ref-x': -20, 'ref-y': -20}
http://jsfiddle.net/9a8brrun/1/

JointJS creating custom Shapes, Diamond, Hexagon

I m new to jointJS, I need to create custom shapes using JointJS, I have tried creating the diamond shape using the Rectangle, making its height and width same, and then rotate by 45 degrees as follows,
var diamond = new joint.shapes.basic.Rect({
position: { x: 100, y: 100 },
size: { width: 100, height: 100 },
attrs: { diamond: { width: 100, height: 30 } }
});
diamond.attr({
rect: { fill: '#cccccc', 'stroke-width': 2, stroke: 'black' },
text: {
text: 'Diamond', fill: '#3498DB',
'font-size': 18, 'font-weight': 'bold',
'font-variant': 'small-caps',
'text-transform': 'capitalize'
}
});
diamond.rotate(45);
However, the text present inside the rectangle also gets rotated, Any Ideas how can i proceed.... Also I need to create hexagon with a label... Any help will be much appreciated ....
Thanks In Advance,
Mayuri
There is no need to rotate the whole element. Try to add a transform attribute to joint.dia.basic.Rect model.
rect: { transform: 'rotate(45)' }
The other option would be to use joint.dia.basic.Path model.
var diamond = new joint.shapes.basic.Path({
size: { width: 100, height: 100 },
attrs: {
path: { d: 'M 30 0 L 60 30 30 60 0 30 z' },
text: {
text: 'Diamond',
'ref-y': .5 // basic.Path text is originally positioned under the element
}
}
});
In order to achieve a hexagon shape, use the joint.dia.basic.Path model again, but this time use the following path data.
path: { d: 'M 50 0 L 0 20 0 80 50 100 100 80 100 20 z'}
Last but least you can create a custom shape with SVG Polygon in its markup.
Thanks a lot Roman, I followed first solution for diamond and it worked liked a charm!!
here is this for any one looking to make diamond shape using joint.js, I have added the following in joint.js
joint.shapes.basic.Diamond = joint.shapes.basic.Generic.extend({
markup: '<g class="rotatable"><g class="scalable"><rect/></g><text/></g>',
defaults: joint.util.deepSupplement({
type: 'basic.Rect',
attrs: {
'rect': { fill: '#FFFFFF', stroke: 'black', width: 1, height: 1,transform: 'rotate(45)' },
'text': { 'font-size': 14, text: '', 'ref-x': .5, 'ref-y': .5, ref: 'rect', 'y-alignment': 'middle', 'x-alignment': 'middle', fill: 'black', 'font-family': 'Arial, helvetica, sans-serif' }
}
}, joint.shapes.basic.Generic.prototype.defaults)
});
And for its implementation as follows,
var diamond = new joint.shapes.basic.Diamond({
position: { x: 100, y: 100 },
size: { width: 100, height: 100 },
attrs: { diamond: { width: 100, height: 30 } }
});
diamond.attr({
rect: { fill: '#cccccc', 'stroke-width': 2, stroke: 'black' },
text: {
text: 'Diamond', fill: '#3498DB',
'font-size': 18, 'font-weight': 'bold',
'font-variant': 'small-caps',
'text-transform': 'capitalize'
}
});

Highcharts renderer.text as export only

I have an optional feature for a chart that adds a renderer.text text object. When the chart is exported I would like this to be added only in that case. Below I have source code on how I have been accessing the renderer and the exporter. In the commented section Insert Here is where I was thinking it might go but I am unsure of the syntax. Thank you
myChart.renderer.text('Filtered', 5, 10)
.attr({rotation: 0})
.css({color: '#4572A7', fontSize: '8px', fontStyle:'italic'})
.add();
myChart.exportChart(null,
{chart:
{backgroundColor: '#FFFFFF', width: 972, height:480 /*Insert Here*/
}
}
);
You are right - there you should use load event to add extra text for exported image: http://jsfiddle.net/3bQne/88/
chart.exportChart(null, {
chart: {
backgroundColor: '#FFFFFF',
width: 972,
height: 480,
events: {
load: function () {
this.renderer.text('Filtered', 5, 10)
.attr({
rotation: 0
})
.css({
color: '#4572A7',
fontSize: '8px',
fontStyle: 'italic'
})
.add();
}
}
}
});

Resources