Can I use iScroll to scrollToElement + offset? - offset

I have this code working...
myScroller.scrollTo(0, -654, 200);
I also have this working....
myScroller.scrollToElement("#p4", "1s");
Is there a way to add offset to the #id, like scrollToElement("#p4" + 100, "1s")?

No you can't.
myScroller.scrollToElement("#p4", "1s");
Because first parameter should be the CSS selector of a DOM element. Therefore can you use "#p4" + 100 for applying CSS rules? If your answer is YES then YOU CAN else YOU CANNOT.
If you wanted to scroll to next element after particular time what you can do is try with nth-child() CSS property with a appropriate timeout and incremental flag. Something like this (Assume your elements are inside a parent DIV element which have id myDiv)
var incre = 0;
function customScrollToElement(){
myScroller.scrollToElement("#myDiv:nth-child(" + incre + ")", 10);
incre ++;
}
setTimeout(function(){
customScrollToElement();
},100);

You can do it with some calculation by first using jQuery to get the element's position relative to their parent.
var left = -1 * ( $('#p4').position().left + 100 ),
top = -1 * ( $('#p4').position().top );
myScroller.scrollTo(left, top, 1000);
That will scroll 100 pixels right of the element

Related

How do i stop clipping of limit line text in ios-charts?

I have a requirement for drawing the limit line which is near to the top of the chart and I want to keep limit line label on top right. Is there any way, it can not be truncated. Please see my output.
enter image description here
try limitline.labelPosition = ChartLimitLabelPositionRightBottom;
if you want keep labelPosition on top right,
you may can try set yourYAxis.spaceTop = x;
if x == 0, the maxValue will match the top of the chart,
if x == 1, the maxValue will match the centerY of the chart,
sorry, I can't express myself well, but, just try it.
hope it works.
The default renderer is little bit messed up. Subclass it (YAxisRenderer) and override method: renderLimitLines. Copy the content from original renderer and replace lines:
var clippingRect = viewPortHandler.contentRect
clippingRect.origin.y -= l.lineWidth / 2.0
clippingRect.size.height += l.lineWidth
with:
var clippingRect = viewPortHandler.contentRect
clippingRect.origin.y -= l.lineWidth / 2.0 + l.valueFont.lineHeight
clippingRect.size.height += l.lineWidth + l.valueFont.lineHeight
Now, as you have it prepared, you need to set your new axis renderer for
let yAxisRenderer = CenteredLimitLineYAxisRenderer(
viewPortHandler: chart.viewPortHandler,
yAxis: chart.leftAxis,
transformer: chart.getTransformer(forAxis: .left)
)
chart.leftYAxisRenderer = yAxisRenderer

Merging geometries using a WebWorker?

Anyone know if it's possible to merge a set of cube geometries in a web worker and pass it back to the main thread? Was thinking this could reduce the lag when merging large amounts of cubes.
Does Three.JS work okay in a web worker, and if it does, would it be possible (and faster) to do this? Not sure if passing the geometry back would take just as long as merging it normally.
At the moment I'm using a timed for loop to reduce the lag:
// This array is populated by the server and contains the chunk position and data (which I do nothing with yet).
var sectionData = data.secData;
var section = 0;
var tick = function() {
var start = new Date().getTime();
for (; section < sectionData.length && (new Date().getTime()) - start < 1; section++) {
var sectionXPos = sectionData[section][0] * 10;
var sectionZPos = sectionData[section][1] * 10;
var combinedGeometry = new THREE.Geometry();
for (var layer = 0; layer < 1; layer++) { // Only 1 layer because of the lag...
for (var x = 0; x < 10; x++) {
for (var z = 0; z < 10; z++) {
blockMesh.position.set(x-4.5, layer-.5, z-4.5);
blockMesh.updateMatrix();
THREE.GeometryUtils.merge(combinedGeometry, blockMesh);
}
}
}
var sectionMesh = new THREE.Mesh(combinedGeometry, grassBlockMat);
sectionMesh.position.set(sectionXPos, 0, sectionZPos);
sectionMesh.matrixAutoUpdate = false;
sectionMesh.updateMatrix();
scene.add(sectionMesh);
}
if (section < sectionData.length) {
setTimeout(tick, 25);
}
};
setTimeout(tick, 25);
Using Three.JS rev59-dev.
Merged cubes make up the terrain in chunks, and at the moment (due to the lag) each chunk only has 1 layer.
Any tips would be appreciated! Thanks.
THREE.JS will not work in a web worker, however you can copy those parts of the library that you need to work both in the main thread and in your web worker.
Your first problem will be that you cannot send the geometry object itself back to the main thread.
Since the web worker onmessage variable passing works only by sending copies of JSON (not javascript objects) or references to ArrayBuffers, you would have to decode the geometry down to each float, pack it in an ArrayBuffer, and send a reference back to the main thread.
Note those are called transferable objects and once sent, they are cleared in the webworker / main thread from which they came.
See here for more details:
http://www.html5rocks.com/en/tutorials/workers/basics/
https://developer.mozilla.org/en-US/docs/Web/Guide/Performance/Using_web_workers
Here is an example of packing position vertices into an array for a physics type system:
//length * 3 axes * 4 bytes per vertex
var posBuffer = new Float32Array(new ArrayBuffer(len * 3 * 4));
//in a loop
//... do hard work
posBuffer[i * 3] = pos.x; //pos is a threejs vector
posBuffer[i * 3 + 1] = pos.y;
posBuffer[i * 3 + 2] = pos.z;
//after loop send buffer to main thread
self.postMessage({posBuffer:posBuffer}, [posBuffer.buffer]);
I copied the THREE.JS vector class inside my web worker and cut out all the methods I didn't need to keep it nice and lean.
FYI it's not slow and for something like n-body collisions it works well.
The main thread sends a command to the web worker telling it to run the update and then listens for the response. Kind of like a producer consumer model in regular threading.

Particle ID and retrieving multiple IDs in Three.js

I am trying to create particles with three.js, currently as a particle system.
The goal of the project is to create particles, with defined positions and unique IDs, and add an option to select multiple particles and retrieve their IDs.
I did some research, but found only ways to detect the position of a mouse-click.
So, I'm looking for the following information:
First: Is there an option to assign IDs to single particles (as simple as a number)?
Second: Is there a way to select multiple particles and view their IDs in a (popup) window?
Thanks for your Help!
PS: I found, that you can assign IDs to THREE.ParticleDOMMaterial (I don't know, what this function does!?) and THREE.ParticleBasicMaterial (Assign an ID to the material, but not to the particle itself).
All Object3D instances have a unique id in three.js by default and Particle inherits that. Also Object3D has a name property, if that helps.
Here's a little snippet which illustrates naming particles:
for ( var i = 0; i < 100; i++ ) {
particle = new THREE.Particle( new THREE.ParticleCanvasMaterial( { color: Math.random() * 0x808008 + 0x808080, program: program } ) );
particle.name = "particle"+i;
particle.position.x = Math.random() * 2000 - 1000;
particle.position.y = Math.random() * 2000 - 1000;
particle.position.z = Math.random() * 2000 - 1000;
particle.scale.x = particle.scale.y = Math.random() * 10 + 5;
group.add( particle );
}
and here's an example of a mouse down event handler which prints the name and id of the clicked particle in the console:
function onDocumentMouseDown( event ) {
event.preventDefault();
var vector = new THREE.Vector3( ( event.clientX / window.innerWidth ) * 2 - 1, - ( event.clientY / window.innerHeight ) * 2 + 1, 0.5 );
projector.unprojectVector( vector, camera );
var ray = new THREE.Ray( camera.position, vector.subSelf( camera.position ).normalize() );
var intersects = ray.intersectScene( scene );
if ( intersects.length > 0 ) {
console.log("you clicked particle named '" + intersects[0].object.name + "' with id: " + intersects[0].object.id);
}
}
Goodluck!

coffeescript for loop refactoring

I am quite new to coffeescript and I am wondering if any more experienced users could point suggest a refactoring for the following code:
splitCollection: =>
maxLength = Math.ceil(#collection.length / 3)
sets = Math.ceil(#collection.length / maxLength)
start = 0
for x in [1..sets]
if x != sets
#render new BusinessUnits(#collection.models.slice(start, (maxLength + start)))
else
#render new BusinessUnits(#collection.models.slice(start, (#collection.length)))
start+= maxLength
There does not appear to be a while loop in coffeescript which seems to suggest a better mechanism.
Any suggestions appreciated.
Looks like you are using Backbone.js, which includes Underscore.js, which has the groupBy function.
You could create a "bucketNumber" function:
bucketNumber = (value, index) ->
Math.floor( index / #collection.length * 3 )
Then group your collection:
sets = #collection.groupBy bucketNumber
Now, assuming ten items, sets should look something like this:
{0: [{}, {}, {}], 1: [{}, {}, {}], 2: [{}, {}, {}, {}]}
From here, it becomes rather straight-forward
for bucketNumber, bucket of sets
#render new BusinessUnits( bucket )
Here is a jsFiddle showing it in action
You don't need to keep track of your position twice, x is enough:
splitCollection: =>
setSize = Math.ceil #collection.length / 3
sets = Math.ceil #collection.length / maxLength
for x in [1..sets]
#render new BusinessUnits #collection.models[x * setSize...(x+1) * setSize]
Note that there is nothing wrong with passing slice an end greater than the array length.
If I understand your code, you want to split an array in 3 parts (the last one can have less items). In this case write the reusable abstraction for the task. Using underscore:
splitCollection: =>
group_size = Math.ceil(#collection.size() / 3)
_.each _(#collection.models).inGroupsOf(group_size), (group) ->
#render(new BusinessUnits(group))
_.inGroupsOf can be written:
_.mixin({
inGroupsOf: function(array, n) {
var output = [];
for(var index=0; index < array.length; index += n) {
output.push(array.slice(index, index+n));
}
return output;
}
});

fpdf multicell issue

how we display fpdf multicell in equal heights having different amount of content
Great question.
I solved it by going through each cell of data in your row that will be multicelled and determine the largest height of all these cells. This happens before you create your first cell in the row and it becomes the new height of your row when you actually go to render it.
Here's some steps to achieve this for just one cell, but you'll need to do it for every multicell:
This assumes a $row of data with a String attribute called description.
First, get cell content and set the column width for the cell.
$description = $row['desciption']; // MultiCell (multi-line) content.
$column_width = 50;
Get the width of the description String by using the GetStringWidth() function in FPDF:
$total_string_width = $pdf->GetStringWidth($description);
Determine the number of lines this cell will be:
$number_of_lines = $total_string_width / ($column_width - 1);
$number_of_lines = ceil( $number_of_lines ); // Round it up.
I subtracted 1 from the $column_width as a kind of cell padding. It produced better results.
Determine the height of the resulting multi-line cell:
$line_height = 5; // Whatever your line height is.
$height_of_cell = $number_of_lines * $line_height;
$height_of_cell = ceil( $height_of_cell ); // Round it up.
Repeat this methodology for any other MultiCell cells, setting the $row_height to the largest $height_of_cell.
Finally, render your row using the $row_height for your row's height.
Dance.
I was also getting same issue when i have to put height equal to three lines evenif i have content of half or 1 and half line, i solved this by checking if in a string no of elements are less than no of possible letters in a line it is 60. If no of letters are less or equal to one line then ln() is called for two empty lines and if no of words are equal to or less than 2 line letters then one ln() is called.
My code is here:
$line_width = 60; // Line width (approx) in mm
if($pdf->GetStringWidth($msg1) < $line_width)
{
$pdf->MultiCell(75, 8, $msg1,' ', 'L');
$pdf->ln(3);
$pdf->ln(3.1);
}
else{
$pdf->MultiCell(76, 4, $msg1,' ', 'L');
$pdf->ln(3.1);
}
Ok I've done the recursive version. Hope this helps even more to the cause!
Take in account these variables:
$columnLabels: Labels for each column, so you'll store data behind each column)
$alturasFilas: Array in which you store the max height for each row.
//Calculate max height for each column for each row and store the value in //////an array
$height_of_cell = 0;
$alturasFilas = array();
foreach ( $data as $dataRow ) {
for ( $i=0; $i<count($columnLabels); $i++ ) {
$variable = $dataRow[$i];
$total_string_width = $pdf->GetStringWidth($variable);
$number_of_lines = $total_string_width / ($columnSizeWidth[$i] - 1);
$number_of_lines = ceil( $number_of_lines ); // Redondeo.
$line_height = 8; // Altura de fuente.
$height_of_cellAux = $number_of_lines * $line_height;
$height_of_cellAux = ceil( $height_of_cellAux );
if($height_of_cellAux > $height_of_cell){
$height_of_cell = $height_of_cellAux;
}
}
array_push($alturasFilas, $height_of_cell);
$height_of_cell = 0;
}
//--END--
Enjoy!
First, it's not the question to get height of Multicell. (to #Matias, #Josh Pinter)
I modified answer of #Balram Singh to use this code for more than 2 lines.
and I added new lines (\n) to lock up height of Multicell.
like..
$cell_width = 92; // Multicell width in mm
$max_line_number = 4; // Maximum line number of Multicell as your wish
$string_width = $pdf->GetStringWidth($data);
$line_number = ceil($string_width / $cell_width);
for($i=0; $i<$max_line_number-$line_number; $i++){
$data.="\n ";
}
Of course you have to assign SetFont() before use GetStringWidth().
My approach was pretty simple. You already need to override the header() and footer() in the fpdf class.
So i just added a function MultiCellLines($w, $h, $txt, $border=0, $align='J', $fill=false).
That's a very simple copy of the original MultiCell. But it won't output anything, just return the number of lines.
Multiply the lines with your line-height and you're safe ;)
Download for my code is here.
Just rename it back to ".php" or whatever you like. Have fun. It works definitely.
Mac
My personal solution to reduce the font size and line spacing according to a preset box:
// set box size and default font size
$textWidth = 100;
$textHeight = 100;
$fontsize = 12;
// if you get text from html div (using jquery and ajax) you must replace every <br> in a new line
$desc = utf8_decode(str_replace('<br>',chr(10),strip_tags($_POST['textarea'],'<br>')));
// count newline set in $desc variable
$countnl = substr_count($desc, "\n");
// Create a loop to reduce the font according to the contents
while($pdf->GetStringWidth($desc) > ($textWidth * (($textHeight-$fontsize*0.5*$countnl) / ($fontsize*0.5)))){
$fontsize--;
$pdf->SetFont('Arial','', $fontsize);
}
// print multicell and set line spacing
$pdf->MultiCell($textWidth, ($fontsize*0.5), "$desc", 0, 'L');
That's all!
A better solution would be to use your own word wrap function, as FPDF will not cut words, so you do not have to rely on the MultiCell line break.
I have wrote a method that checks for every substring of the text if the getStringWidth of FPDF is bigger than the column width, and splits accordingly.
This is great if you care more about a good looking PDF layout, than performance.
public function wordWrapMultiCell($text, $cellWidth = 80) {
$explode = explode("\n", $text);
array_walk($explode, 'trim');
$lines = [];
foreach($explode as $split) {
$sub = $split;
$char = 1;
while($char <= strlen($sub)) {
$substr = substr($sub, 0, $char);
if($this->pdf->getStringWidth($substr) >= $cellWidth - 1) { // -1 for better getStringWidth calculating
$pos = strrpos($substr, " ");
$lines[] = substr($sub, 0, ($pos !== FALSE ? $pos : $char)).($pos === FALSE ? '-' : '');
if($pos !== FALSE) { //if $pos returns FALSE, substr has no whitespace, so split word on current position
$char = $pos + 1;
$len = $char;
}
$sub = ltrim(substr($sub, $char));
$char = 0;
}
$char++;
}
if(!empty($sub)) {
$lines[] = $sub;
}
}
return $lines;
}
This returns an array of text lines, which you could merge by using implode/join:
join("\r\n", $lines);
And what it was used for in the first place, get the line height:
$lineHeight = count($lines) * $multiCellLineHeight;
This only works for strings with a space character, no white spacing like tabs. You could replace strpos with a regexp function then.