How to evenly distribute the components by width in a Row? - components

I'm using Appcelerator Titanium and want to make an Android application. I created a TableView with 4 rows. I want to put 3 labels into each row and I want my labels to be evenly distributed. (1st label must be at the left, 2nd at the center, and 3rd at the right of the row.)
Thank you.

For left, center, right, you can use relative positioning and text alignment to very simply make your rows. This approach works well regardless of how wide the current screen is (ie, this works on tablet, phone, TV, etc).
var win = Ti.UI.createWindow({
backgroundColor: '#fff'
});
var rows = [];
for (var i = 0; i < 10; i++) {
var row = Ti.UI.createTableViewRow();
row.add(Ti.UI.createLabel({
text: 'Left ' + i, textAlign: 'left',
color: '#000',
left: 10
}));
row.add(Ti.UI.createLabel({
text: 'Center ' + i, textAlign: 'center',
color: '#000'
}));
row.add(Ti.UI.createLabel({
text: 'Right ' + i, textAlign: 'right',
color: '#000',
right: 10
}));
rows.push(row);
}
win.add(Ti.UI.createTableView({
data: rows
}));
win.open();
Another option would be to use percent widths, like left: '0%', width: '33%', then left: '33%', width: '33%', etc.
Or you could say the first label is from left: 0, width: 200. The second is left: 200, width: 50, and the third is from left: 250, right: 0. That would give you a third label that is elastic so it can take up al the space.
Yet another option (that I don't recommend you take) would be to use Ti.Platform.displayCaps.platformWidth and position the row elements based on that. But that would be very fragile to orientation changes.
It all depends on your content. With these in hand, you should be able to handle your particular use case.

Here is how I recently solved this issue. With 3 separate views and labels inside each row. This worked very well for me! All of them are based on percents, so it should work on all resolutions. Good luck!
for (var i = 0; i < 4; i++) {
var row = Ti.UI.createTableViewRow({
height: 'auto',
});
var view1 = Ti.UI.createView({
left : 0,
width : "33.33%",
backgroundColor:'red',
height:40
});
var label1 = Ti.UI.createLabel({
text: 'here',
color:"#fff",
textAlign: Ti.UI.TEXT_ALIGNMENT_LEFT
});
view1.add(label1);
var view2 = Ti.UI.createView({
left : "33.33%",
width : "33.33%",
backgroundColor : "white",
height:40
});
var label2 = Ti.UI.createLabel({
text: 'there',
color:"#fff"
});
view2.add(label2);
var view3 = Ti.UI.createView({
left : "66.66%",
width : "33.33%",
backgroundColor: "blue",
height:40
});
var label3 = Ti.UI.createLabel({
text: 'Everywhere',
color:"#fff"
});
view3.add(label3);
row.add(view1);
row.add(view2);
row.add(view3);
}

try this code.
var win = Ti.UI.createWindow({
});
var table = Ti.UI.createTableView({
backgroundColor:'blue',
top:50,
height : 160
});
win.add(table);
var data = [];
for (var i = 0; i < 4; i++) {
var row = Ti.UI.createTableViewRow({
height : 40
});
var label1 = Ti.UI.createLabel({
text : 'label1',
top : 5,
left : 10,
width : 80,
height : 30
});
row.add(label1);
var label2 = Ti.UI.createLabel({
text : 'label2',
top : 5,
left : 130,
width : 80,
height : 30
});
row.add(label2);
var label3 = Ti.UI.createLabel({
text : 'label3',
top : 0,
left : 240,
width : 80,
height : 30
});
row.add(label3);
data.push(row);
}
table.data = data;
win.open();
Best luck..

Related

Set coords for Bounding Rect of a Path after moving it in fabricjs

There are dozen of topics on Stackoverflow on this problem, none of them shows a solution. So the problem is painful for many.
The problem: when I move a path, it's BoundingRect is not moving.
Possible solutions:
the creators of the library recommend _setPath method, but there are no examples, I can't understand how to use it;
Somehow to set Left, Top, Width and Height separately to the bounding rect (pathLine.getBoundingRect()). I don't know how, it's not working with Set().
To set Left, Top, Width and Height to the path. If I do so, the bounding rect is correct, but pathline is also shifting. I can't make it work.
delete and add path from canvas every time it moves. Bad solution :(
Remarkable that _calcDimensions() works correct with path coords.
Which means there are methods that work with path, we just need to find a proper one.
var pathLine = new fabric.Path('M 10 10 L 10 100 L 100 100', {
fill: '',
stroke: 'black',
objectCaching: false
})
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'grey',
width: 50,
height: 50,
});
function createCanvas(id){
canvas = new fabric.Canvas(id);
canvas.add(pathLine);
canvas.add(rect);
pathLine.perPixelTargetFind = true;
canvas.on('object:moving', function(e) {
rect.setCoords();
const { width, height, left, top } = pathLine._calcDimensions();
var bound = pathLine.getBoundingRect();
pathLine.path[2][1] = rect.left ;
pathLine.path[2][2] = rect.top ;
canvas.renderAll();
});
return canvas;
}
Any ideas?

How to get top left of an object inside group fabricjs

How can I get canvas-relative position (top, left) of triangle inside an group as bellow image?
I followed this topic: How to get the canvas-relative position of an object that is in a group? but it only right when group is not rotated.
Working example you may find here: http://jsfiddle.net/mmalex/2rsevdLa/
Fabricjs provides a comprehensive explanation of how transformations are applied to the objects: http://fabricjs.com/using-transformations
Quick answer: the coordinates of an object inside the group is a point [0,0] transformed exactly how the object in the group was transformed.
Follow my comments in code to get the idea.
// 1. arrange canvas layout with group of two rectangles
var canvas = new fabric.Canvas(document.getElementById('c'));
var rect = new fabric.Rect({
width: 100,
height: 100,
left: 50,
top: 50,
fill: 'rgba(255,0,0,0.25)'
});
var smallRect = new fabric.Rect({
width: 12,
height: 12,
left: 150 - 12,
top: 50 + 50 - 12 / 2 - 10,
fill: 'rgba(250,250,0,0.5)'
});
// 2. add a position marker (red dot) for visibility and debug reasons
var refRect = new fabric.Rect({
width: 3,
height: 3,
left: 100,
top: 100,
fill: 'rgba(255,0,0,0.75)'
});
var group = new fabric.Group([rect, smallRect], {
originX: 'center',
originY: 'center'
});
canvas.add(group);
canvas.add(refRect);
canvas.renderAll();
// 3. calculate coordinates of child object in canvas space coords
function getCoords() {
// get transformation matrixes for object and group individually
var mGroup = group.calcTransformMatrix(true);
// flag true means that we need local transformation for the object,
// i.e. how object is positioned INSIDE the group
var mObject = smallRect.calcTransformMatrix(true);
console.log("group: ", fabric.util.qrDecompose(mGroup));
console.log("rect: ", fabric.util.qrDecompose(mObject));
// get total transformattions that were applied to the child object,
// the child is transformed in following order:
// canvas zoom and pan => group transformation => nested object => nested object => etc...
// for simplicity, ignore canvas zoom and pan
var mTotal = fabric.util.multiplyTransformMatrices(mGroup, mObject);
console.log("total: ", fabric.util.qrDecompose(mTotal));
// just apply transforms to origin to get what we want
var c = new fabric.Point(0, 0);
var p = fabric.util.transformPoint(c, mTotal);
console.log("coords: ", p);
document.getElementById("output").innerHTML = "Coords: " + JSON.stringify(p);
// do some chores, place red point
refRect.left = p.x - 3 / 2;
refRect.top = p.y - 3 / 2;
canvas.bringToFront(refRect);
canvas.renderAll();
}
a very simple way to get topleft is
var cords = object._getLeftTopCoords();
cords.x and cord.y will give you the result

How to add Header and footer content to pdfkit for node.js

I would like to generate a pdf using node js (express). I need to add header and footer to every page with page numbers. Any help would be appreciated.
Thanks.
Adding a Footer on all pages
doc.addPage()
let bottom = doc.page.margins.bottom;
doc.page.margins.bottom = 0;
doc.text('Page 1', 0.5 * (doc.page.width - 100), doc.page.height - 50,
{
width: 100,
align: 'center',
lineBreak: false,
})
// Reset text writer position
doc.text('', 50, 50)
doc.page.margins.bottom = bottom;
let pageNumber = 1;
doc.on('pageAdded', () => {
pageNumber++
let bottom = doc.page.margins.bottom;
doc.page.margins.bottom = 0;
doc.text(
'Pág. ' + pageNumber,
0.5 * (doc.page.width - 100),
doc.page.height - 50,
{
width: 100,
align: 'center',
lineBreak: false,
})
// Reset text writer position
doc.text('', 50, 50);
doc.page.margins.bottom = bottom;
})
You can do this :
doc.text('This is a footer', 20, doc.page.height - 50, {
lineBreak: false
});
Adding content to every page using doc.on('pageAdded'... hook has the nasty side effect of hijacking your position (doc.x/doc.y) while filling in a page. Additionally, you have to set the autoFirstPage: false flag in order to inject your hook prior to first page creation.
I find using bufferPages mode and then making global edit to the pages at the end much more graceful/logical.
const doc = new PDFDocument({
bufferPages: true
});
doc.text("Hello World")
doc.addPage();
doc.text("Hello World2")
doc.addPage();
doc.text("Hello World3")
//Global Edits to All Pages (Header/Footer, etc)
let pages = doc.bufferedPageRange();
for (let i = 0; i < pages.count; i++) {
doc.switchToPage(i);
//Header: Add page number
let oldTopMargin = doc.page.margins.top;
doc.page.margins.top = 0 //Dumb: Have to remove top margin in order to write into it
doc
.text(
`Page: ${i + 1} of ${pages.count}`,
0,
(oldTopMargin/2), // Centered vertically in top margin
{ align: 'center' }
);
doc.page.margins.top = oldTopMargin; // ReProtect top margin
//Footer: Add page number
let oldBottomMargin = doc.page.margins.bottom;
doc.page.margins.bottom = 0 //Dumb: Have to remove bottom margin in order to write into it
doc
.text(
`Page: ${i + 1} of ${pages.count}`,
0,
doc.page.height - (oldBottomMargin/2), // Centered vertically in bottom margin
{ align: 'center' }
);
doc.page.margins.bottom = oldBottomMargin; // ReProtect bottom margin
}
doc.end();
about this library, I suggest to read the PDF documentation, it is a lot must complete that the online HTML doc.
Warning : To be able to write outside the main content area, you have to set height and width on text's function params.
so as seen pdf doc you can do :
const doc = new PDFDocument({bufferPages: true})
//addPage X times
const range = doc.bufferedPageRange();
for( let i = range.start; i < (range.start + range.count); i++) {
doc.switchToPage(i);
doc.text(`Page ${i + 1} of ${range.count}`,
200,
doc.page.height - 40,
{ height : 25, width : 100});
}
this works for me
const doc = new PDFDocument({bufferPages: true})
const range = doc.bufferedPageRange();
for (let i = range.start; i <= (doc._pageBufferStart +
doc._pageBuffer.length - 1); i++) {
doc.switchToPage(i);
doc.font('Times-Roman').fontSize(8).text('Footer', 90,
doc.page.height - 40, {
lineBreak: false
});
}

Graph search for element by element's name in jointJS

I have a problem in Rappid/jointJS
I have in stencil.js 4 shapes(2 basic.Circle and 2 basic.Rect) with names START(basic.Circle), END(basic.Circle), Activity(basic.Rect) and Workitem( basic.Rect) and I want in my main.js from all my graph to get the basic shape with name(I mean with attrs text ) "Activity".
This is the Stencil description for "Activity" :
new joint.shapes.basic.Rect({ size: { width: 5, height: 3 },
attrs: {
rect: {
rx: 2, ry: 2, width: 50, height: 30,
fill: '#0000FF'
},
text: { text: 'Activity', fill: '#ffffff', 'font-size': 10,
stroke: '#000000', 'stroke-width': 0 }
}
}),
How wil I get it? The only way I can search in my graph so far is if a cell has type basic.Circle(use of get('type') === 'basic.Circle')). but with type Circle I have two items:Activity and Workitem.
Is it so difficult to search for the graph element with name : "Activity"?
Thank you in advance
You can obtain all the elements (except for links) from following method
var allElement = graph.getElements()
Next if you want to obtain elements with 'Activity' do as follows
var activityElements = [];
allElement.forEach(elem => {
var textVal = elem.attributes.attrs.text.text;
if(textVal !== undefined && textVal === 'Activity') {
activityElements.push(elem);
}
});
Now the activityElements array will contain all the elements you require.
I solved my problem by taking element data in JSON format:
_.each(this.graph.getElements(), function(element) {
if(element.attributes.attrs["text"]["text"] == "Activity"){
//alert("YEAHHHHHH");
}
});
you could use the api on element as well, element.attr('text') returns the text object from the shape: { text: 'Activity', fill: '#ffffff', 'font-size': 10,
stroke: '#000000', 'stroke-width': 0 }
You could also set an "id" attribute to your shape and use graph.getCell('id_name_goes_here'); which would be much simpler if you didn't mind adding an id field to each shape.

Is it possible to determine a string's width in Appcelerator?

I'm trying to determine the length of a String so I can dynamically layout some Labels. In iOS I would use:
CGSize size = [string sizeWithFont:font];
Is it possible to do this with the Appcelerator API or is there another way to do this type of dynamic layout?
If you create labels with 'auto' width, once they've been constructed you can access their actual width and position any other labels accordingly:
var window = Ti.UI.createWindow();
var label = Ti.UI.createLabel({
text: 'This is a test string',
width: 'auto',
color: '#FFF',
left: 0,
top: 0
});
var labelWidth = label.width;
Ti.API.info(labelWidth);
// Dynamically position the second label
var secondLabel = Ti.UI.createLabel({
text: 'Second label',
width: 100,
left: labelWidth + 10,
top: 0,
color: '#FFF'
});
window.add(label);
window.add(secondLabel);
window.open();
It's not very elegant but it works.
var win = Ti.UI.createWindow({
'layout': 'horizontal'
});
https://github.com/appcelerator/titanium_mobile/blob/master/demos/KitchenSink/Resources/examples/horizontal_layout.js

Resources