I am using YUI and need to get the true width of the element. The width of an element can be determined as follows.
width + border-left + border-right + padding-left + padding-right + margin-left + margin-right.
Below is what I have come up with. It appears to be working. I was just wondering if this is the best way to go about determining this or is there there a more efficient way?
YUI().use('node', function(Y) {
var node = Y.one('#nav');
var nodeWidth = trueElementWidth(node);
alert(nodeWidth);
});
function trueElementWidth(el) {
var width = 0;
var attributes = ['border-left', 'border-right', 'padding-left', 'padding-right', 'width', 'margin-right', 'margin-left'];
for(var i=0; i < attributes.length; i++) {
width = width + removePx(el.getComputedStyle(attributes[i]));
}
return width;
}
function removePx(el) {
el = el.toString();
length = el.length - 2;
elDimension = parseInt(el.substring(0, length));
return isNaN(elDimension) ? 0 : elDimension;
}
There is an offsetWidth property that returns exactly what you want.
Related
We are facing issues in Xamarin grid layout, the sizes are defined in the OnAppearing method. every time if we call OnAppearing method, the size of grid is reducing continuously, not getting exact issue
here is the code
gridLayout.RowDefinitions.Add(new RowDefinition(){
Height = new GridLength(5, GridUnitType.Star),
});
gridLayout.RowDefinitions.Add(new RowDefinition(){
Height = new GridLength(5, GridUnitType.Star),
});
gridLayout.ColumnDefinitions.Add(new ColumnDefinition()
{
Width = new GridLength(2, GridUnitType.Star),
});
gridLayout.ColumnDefinitions.Add(new ColumnDefinition(){
Width = new GridLength(2, GridUnitType.Star),
});
gridLayout.ColumnDefinitions.Add(new ColumnDefinition(){
Width = new GridLength(2, GridUnitType.Star),
});
gridLayout.ColumnDefinitions.Add(new ColumnDefinition(){
Width = new GridLength(2, GridUnitType.Star),
});
gridLayout.ColumnDefinitions.Add(new ColumnDefinition(){
Width = new GridLength(2, GridUnitType.Star),
});
var productIndex = 0;
for (int rowIndex = 0; rowIndex < 2; rowIndex++)
{
for (int columnIndex = 0; columnIndex < 5; columnIndex++)
{
if (productIndex >= CategoryArray.Count)
{
break;
}
var category = CategoryArray[productIndex];
productIndex += 1;
var categoriesView = new CategoriesView
{
BackgroundColor = Color.White
};
if(category.Image == null){
categoriesView.CategoriesImage.Source = "category_logo";
}else{
categoriesView.CategoriesImage.Source = category.Image;
}
//categoriesView.BackgroundColor = Color.Olive;
categoriesView.TextLabel.Text = category.Name;
categoriesView.CategoryId = category.Id.ToString();
gridLayout.Children.Add(categoriesView, columnIndex, rowIndex);
//gridLayout.BackgroundColor = Color.Beige;
}
}
when ever OnAppearing is calling the page is reloading (the is the feature) and the grid size is reducing continuously.
You should declare the Grid structure only once, ideally in Constructor (or in XAML which is called in the constructor). Whenever OnAppearing is called, you are adding 2 new rows and 5 new columns to the existing Grid hence its size is reducing.
Also, by looking at the elements adding logic you've written, you should probably be using ListView with a Grid ViewCell and set the ItemsSource to an ObservableCollection so that it will update automatically
In a polymer control,'my-grid', I'm trying to add style via the below code:
var styleElement = document.createElement('style', 'custom-style');
styleElement.innerHTML = cssText;
Polymer.StyleDefaults.addStyle(styleElement);
Here, the cssText can be string like
.oc-col-id-0{
flex-basis: var(--oc-col-id-0-flex-basis);
-webkit-flex-basis: var(--oc-col-id-0-flex-basis);
}
.oc-col-id-1{
flex-basis: var(--oc-col-id-1-flex-basis);
-webkit-flex-basis: var(--oc-col-id-1-flex-basis);
}
Without this custom variables, I can append the styleElement by
this.$.gridContainer.appendChild(styleElement);
But however, since there are custom variables, I'm not sure how to fix this issue.
After the element is attached, I can't change the --oc-col-id-0-flex-basis value via
this.customStyle['--oc-col-id-0-flex-basis'] = maxWidth + "px";
this.updateStyles();
It looks that the style variables are not applied to the element.
I'm not sure if there is any way to dynamically add/modify the style of the element. I'm not sure if I'm on the right track.
This is what I do in the end to inject the style class dynamically. It solved my problem so far.
var style = this._styles[0];
var text = style.textContent;
var cssText = "";
for (var id of ids)
{
var classStyle = ".col-id-" + id;
var variableProperty = "--col-id-" + id + "-flex-basis";
if (text.indexOf(classStyle) == -1)
{
cssText += classStyle + "{ flex-basis: var(" + variableProperty + ", auto); -webkit-flex-basis: var(" + variableProperty + ", auto);} ";
}
if (this._ownStylePropertyNames.indexOf(variableProperty) == -1)
{
this._ownStylePropertyNames.push(variableProperty);
}
}
if (cssText.length > 0)
{
style.textContent += " " + cssText;
style.__cssRules = null; //trick for rulesForStyle method in Polymer.html
}
So I am using this npm package: node-stl
And its working great. However the regexp syntax, mathematics and geometrical calculations are somewhat confusing to me. Especially all at the same time.
Basically what I want to achieve is to extend the script to calculate the bounding box of the STL.
Here is the main file that calculates the volume and weight of the STL being parsed/read.
var fs = require('fs');
// Vertex
function Vertex (v1,v2,v3) {
this.v1 = Number(v1);
this.v2 = Number(v2);
this.v3 = Number(v3);
}
// Vertex Holder
function VertexHolder (vertex1,vertex2,vertex3) {
this.vert1 = vertex1;
this.vert2 = vertex2;
this.vert3 = vertex3;
}
// transforming a Node.js Buffer into a V8 array buffer
function _toArrayBuffer (buffer) {
var
ab = new ArrayBuffer(buffer.length),
view = new Uint8Array(ab);
for (var i = 0; i < buffer.length; ++i) {
view[i] = buffer[i];
}
return ab;
}
// calculation of the triangle volume
// source: http://stackoverflow.com/questions/6518404/how-do-i-calculate-the-volume-of-an-object-stored-in-stl-files
function _triangleVolume (vertexHolder) {
var
v321 = Number(vertexHolder.vert3.v1 * vertexHolder.vert2.v2 * vertexHolder.vert1.v3),
v231 = Number(vertexHolder.vert2.v1 * vertexHolder.vert3.v2 * vertexHolder.vert1.v3),
v312 = Number(vertexHolder.vert3.v1 * vertexHolder.vert1.v2 * vertexHolder.vert2.v3),
v132 = Number(vertexHolder.vert1.v1 * vertexHolder.vert3.v2 * vertexHolder.vert2.v3),
v213 = Number(vertexHolder.vert2.v1 * vertexHolder.vert1.v2 * vertexHolder.vert3.v3),
v123 = Number(vertexHolder.vert1.v1 * vertexHolder.vert2.v2 * vertexHolder.vert3.v3);
return Number(1.0/6.0)*(-v321 + v231 + v312 - v132 - v213 + v123);
}
// parsing an STL ASCII string
function _parseSTLString (stl) {
var totalVol = 0;
// yes, this is the regular expression, matching the vertexes
// it was kind of tricky but it is fast and does the job
var vertexes = stl.match(/facet\s+normal\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+outer\s+loop\s+vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+endloop\s+endfacet/g);
vertexes.forEach(function (vert) {
var preVertexHolder = new VertexHolder();
vert.match(/vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s/g).forEach(function (vertex, i) {
var tempVertex = vertex.replace('vertex', '').match(/[-+]?[0-9]*\.?[0-9]+/g);
var preVertex = new Vertex(tempVertex[0],tempVertex[1],tempVertex[2]);
preVertexHolder['vert'+(i+1)] = preVertex;
});
var partVolume = _triangleVolume(preVertexHolder);
totalVol += Number(partVolume);
})
var volumeTotal = Math.abs(totalVol)/1000;
return {
volume: volumeTotal, // cubic cm
weight: volumeTotal * 1.04 // gm
}
}
// parsing an STL Binary File
// (borrowed some code from here: https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/STLLoader.js)
function _parseSTLBinary (buf) {
buf = _toArrayBuffer(buf);
var
headerLength = 80,
dataOffset = 84,
faceLength = 12*4 + 2,
le = true; // is little-endian
var
dvTriangleCount = new DataView(buf, headerLength, 4),
numTriangles = dvTriangleCount.getUint32(0, le),
totalVol = 0;
for (var i = 0; i < numTriangles; i++) {
var
dv = new DataView(buf, dataOffset + i*faceLength, faceLength),
normal = new Vertex(dv.getFloat32(0, le), dv.getFloat32(4, le), dv.getFloat32(8, le)),
vertHolder = new VertexHolder();
for(var v = 3; v < 12; v+=3) {
var vert = new Vertex(dv.getFloat32(v*4, le), dv.getFloat32((v+1)*4, le), dv.getFloat32( (v+2)*4, le ) );
vertHolder['vert'+(v/3)] = vert;
}
totalVol += _triangleVolume(vertHolder);
}
var volumeTotal = Math.abs(totalVol)/1000;
return {
volume: volumeTotal, // cubic cm
weight: volumeTotal * 1.04 // gm
}
}
// NodeStl
// =======
// > var stl = NodeStl(__dirname + '/myCool.stl');
// > console.log(stl.volume + 'cm^3');
// > console.log(stl.weight + 'gm');
function NodeStl (stlPath) {
var
buf = fs.readFileSync(stlPath),
isAscii = true;
for (var i=0, len=buf.length; i<len; i++) {
if (buf[i] > 127) { isAscii=false; break; }
}
if (isAscii)
return _parseSTLString(buf.toString());
else
return _parseSTLBinary(buf);
}
module.exports = NodeStl;
If anyone could help me with this it would be great. I know and it feels like it simple. That I just need to know max/min of the different directions(x,y,z) and could then calculate the bounding box.
But I do not understand what the max/min for x,y and z is here. Please answer if you have an idea.
I've made a new branch https://github.com/johannesboyne/node-stl/tree/boundingbox could you please verify whether the applied algorithm works?
Best,
Johannes
Edit: If the branch is stable -> works I'll push it into v.0.1.0 (don't know why it is still 0.0.1)
I continue my work on collaborative sketch tool and trying to add retina devices support. Currently i have following behavior if user creating drawing on ipad air:
small movie
Here is my code:
this.getZoomLevel = function (height) {
if (height > 1024) {
return 1024 / height;
} else {
return height / 1024;
}
};
this.calculateCanvasSize = function(pHeight, pWidth) {
var result = {
height: 0,
width: 0
};
while (result.width < pWidth - 1 && result.height < pHeight - 1) {
result.height = result.height + 1;
result.width = result.height * 4 / 3;
}
return result;
};
this.initCanvas = function () {
try {
var parent = document.getElementsByClassName('komaso-canvas-container')[0];
var canvasSize = this.calculateCanvasSize(parent.clientHeight, parent.clientWidth);
var canvasHtml = "<div id='wrapper-" + this.Id + "' class='whiteboard-canvas-wrapper' data-ng-show='CurrentPage.Id==" + this.Id + "'><canvas width='" + canvasSize.width + "' height='" + canvasSize.height + "' id='whiteboard-" + this.Id + "' class='whiteboard'><p>Your brower does not support Canvas/p></canvas></div>";
$(parent).append($compile(canvasHtml)(scope));
this.Canvaso = document.getElementById(this.HtmlId);
if (!this.Canvaso) {
console.log('Error: Cannot find the imageView canvas element!');
return;
}
if (!this.Canvaso.getContext) {
console.log('Error: no canvas.getContext!');
return;
}
this.FabricCanvas = new fabric.Canvas(this.HtmlId, { selectionColor: 'transparent' });
this.FabricCanvas.setWidth(canvasSize.width);
this.FabricCanvas.setHeight(canvasSize.height);
fabric.Object.prototype.transparentCorners = false;
this.FabricCanvas.on('mouse:down', this.onMouseDown);
this.FabricCanvas.on('mouse:up', this.onMouseUp);
this.FabricCanvas.on('mouse:move', this.onMouseMove);
this.FabricCanvas.on('object:added', this.onObjectAdded);
this.FabricCanvas.on('text:editing:exited', self.onTextObjectEdited);
if (window.devicePixelRatio !== 1) {
var c = this.FabricCanvas.getElement();
var w = c.width, h = c.height;
c.setAttribute('width', w * window.devicePixelRatio);
c.setAttribute('height', h * window.devicePixelRatio);
$(c).width(canvasSize.width);
$(c).height(canvasSize.height);
c.getContext('2d').scale(window.devicePixelRatio, window.devicePixelRatio);
}
this.FabricCanvas.setZoom(this.getZoomLevel(this.Canvaso.height));
this.ToggleTool(self.CurrentTool.ToolName);
this.WhiteboardInitiated = true;
} catch (e) {
console.log(e);
}
};
getZoomLevel returns value to pass into SetZoom method of fabric js canvas object. We decided to have all clients canvas aspects are 4:3 and default dimension is 1024*768. So based on this dimensions we calculation zoom factor.
calculateCanvasSize - returns width and height for canvas according to 4:3 rule.
If you have any idea about how to fix this wrong behavior then post your comment please. Thank you in advance!
I would suggest you yo update to a retina enabled version of fabricjs (grab 1.6.2).
If, for any reason you can't, i think the problem is here:
if (window.devicePixelRatio !== 1) {
var c = this.FabricCanvas.getElement();
...
c.getContext('2d').scale(window.devicePixelRatio, window.devicePixelRatio);
}
getContext return a new context. This is not the context where fabric is gonna render later. If you want to have retina enabled lowerCanvas you have to scale this.FabricCanvas.contextContainer that gets created and referenced on fabric.Canvas initialization.
I suggest you to switch to newer fabric anyway.
I have two curved paths, both roughly going from left to right, one above the . I need to join them up with straight lines into a closed path.
To do this, I am assuming I need to build the path string of the big closed path. But in order to build the path, I need to reverse the second curve.
How can I reverse a path in Raphael.js? Or is there a better way to do what I want to do?
Thanks.
Can you try using this example?
It creates 2 independent paths running left to right. Then it merges these into a closed path.
Try in JSFiddle.
EDITED:
var paper = Raphael(0, 0, 800, 600);
// Define 2 paths running left to right
var path1 = paper.path("M10 10L200 120 300 80 400 100 450 150")
.attr({stroke: "#00FF00"}),
path2 = paper.path("M10 200L200 220 300 280 400 300 450 250")
.attr({stroke: "#00FF00"}),
closedPath = joinPaths(path1, path2)
.attr({
fill: "#FF0000",
stroke: "#0000FF"
});
// This function is a poc and assumes that
// the paths contain a "M" at the begining
// and that that "M" is replacable by "L" (absolute Line to)
function joinPaths() {
var i,
len = arguments.length,
pathArr =[],
finalPathArr =[];
for (i = 0; i < len; i++) {
pathArr[i] = arguments[i].attr("path");
if (i) {
pathArr[i][0][0] = "L";
pathArr[i].reverse();
if (i === len-1) {
pathArr[i].push("Z");
}
}
finalPathArr = finalPathArr.concat(pathArr[i]);
}
return paper.path(finalPathArr);
}
I needed this functionality recently to fill the area between to curves on a graph. I used the following implementation.
function reversePath(pathString) {
var pathPieces = pathString.match(/[MLHVCSQTA][-0-9.,]*/gi);
var reversed = '';
var skip = true;
var previousPathType;
for (var i = pathPieces.length - 1; i >= 0; i--) {
var pathType = pathPieces[i].substr(0, 1);
var pathValues = pathPieces[i].substr(1);
switch (pathType) {
case 'M':
case 'L':
reversed += (skip ? '' : pathType) + pathValues;
skip = false;
break;
case 'C':
var curvePieces = pathValues.match(/^([-0-9.]*,[-0-9.]*),([-0-9.]*,[-0-9.]*),([-0-9.]*,[-0-9.]*)$/);
reversed += curvePieces[3] + pathType + curvePieces[2] + ',' + curvePieces[1] + ',';
skip = true;
break;
default:
alert('Not implemented: ' + pathType);
break;
}
}
return reversed;
}
And I would call it like so:
var combinedPath = path1 + 'L' + reversePath(path2) + 'Z';