jQuery Mobile Slider decimal output issue in ipad - ipad

I need help this time.
Developing poker client right now and one issue just gets me.
Just can't get slider bubble to output properly decimal numbers.
Slider image: http://norwaydict.com/slider.jpg
I'm using Jquery mobile slider plugin.
The output in desktop browsers is OK, but the in ipad is not the same:
in ipad decimal number output correctly, but not when number is 1 or 0.40
it should output 1.00 or 0.40 but outputs 1 or 0.4, somehow rounds those numbers.
The plugin code if it helps:
/*!
* jQuery Mobile v1.0b2
* http://jquerymobile.com
* Copyright 2010, jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*/
/*!
* jQuery UI Widget #VERSION
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Widget
*/
/*
* jQuery Mobile Framework : "slider" plugin
* Copyright (c) jQuery Project
* Dual licensed under the MIT or GPL Version 2 licenses.
* Forked by Elmundio87 to add vertical orientation
* http://jquery.org/license
*/
( function( $, undefined ) {
$.widget( "mobile.slider", $.mobile.widget, {
options: {
theme: null,
trackTheme: null,
disabled: false,
initSelector: "input[type='range'], :jqmData(type='range'), :jqmData(role='slider')"
},
_create: function() {
// TODO: Each of these should have comments explain what they're for
var self = this,
control = this.element,
parentTheme = control.parents( "[class*='ui-bar-'],[class*='ui-body-']" ).eq( 0 ),
parentTheme = parentTheme.length ? parentTheme.attr( "class" ).match( /ui-(bar|body)-([a-z])/ )[ 2 ] : "c",
theme = this.options.theme ? this.options.theme : parentTheme,
trackTheme = this.options.trackTheme ? this.options.trackTheme : parentTheme,
cType = control[ 0 ].nodeName.toLowerCase(),
selectClass = ( cType == "select" ) ? "ui-slider-switch" : "",
controlID = control.attr( "id" ),
labelID = controlID + "-label",
label = $( "[for='"+ controlID +"']" ).attr( "id", labelID ),
val = function() {
//$('#pool_balance_cashier').html('Slider value3: ' + parseFloat( control.val() ).toFixed(1));
return cType == "input" ? parseFloat( control.val() ).toFixed(2) : control[0].selectedIndex;
},
min = cType == "input" ? parseFloat( control.attr( "min" ) ) : 0,
max = cType == "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length-1,
sliderOrientation = control.attr( "sliderOrientation") || "horizontal",
step = window.parseFloat( control.attr( "step" ) || 1 ),
//step = (cType === "input") ? parseFloat(control.attr("step")) : 0,
slider = $( "<div class='ui-slider-" + sliderOrientation + " " + selectClass + " ui-btn-down-" + trackTheme +
" ui-btn-corner-all' role='application'></div>" ),
handle = $( "<a href='#' class='ui-slider-handle-"+sliderOrientation +"'></a>" )
.appendTo( slider )
.buttonMarkup({ corners: true, theme: theme, shadow: true })
.attr({
"role": "slider",
"aria-valuemin": min,
"aria-valuemax": max,
"aria-valuenow": val(),
"aria-valuetext": val(),
"title": val(),
"aria-labelledby": labelID
}),
options;
$.extend( this, {
slider: slider,
handle: handle,
dragging: false,
beforeStart: null
});
if ( cType == "select" ) {
slider.wrapInner( "<div class='ui-slider-inneroffset'></div>" );
options = control.find( "option" );
control.find( "option" ).each(function( i ) {
var side = !i ? "b":"a",
corners = !i ? "right" :"left",
theme = !i ? " ui-btn-down-" + trackTheme :" ui-btn-active";
$( "<div class='ui-slider-labelbg ui-slider-labelbg-" + side + theme + " ui-btn-corner-" + corners + "'></div>" )
.prependTo( slider );
$( "<span class='ui-slider-label ui-slider-label-" + side + theme + " ui-btn-corner-" + corners + "' role='img'>" + $( this ).text() + "</span>" )
.prependTo( handle );
});
}
label.addClass( "ui-slider" );
// monitor the input for updated values
control.addClass( cType === "input" ? "ui-slider-input" : "ui-slider-switch" )
.change( function() {
self.refresh( val(), true );
})
.keyup( function() { // necessary?
self.refresh( val(), true, true );
})
.blur( function() {
self.refresh( val(), true );
});
// prevent screen drag when slider activated
$( document ).bind( "vmousemove", function( event ) {
if ( self.dragging ) {
self.refresh( event );
return false;
}
});
slider.bind( "vmousedown", function( event ) {
self.dragging = true;
if ( cType === "select" ) {
self.beforeStart = control[0].selectedIndex;
}
self.refresh( event );
return false;
});
slider.add( document )
.bind( "vmouseup", function() {
if ( self.dragging ) {
self.dragging = false;
if ( cType === "select" ) {
if ( self.beforeStart === control[ 0 ].selectedIndex ) {
//tap occurred, but value didn't change. flip it!
self.refresh( !self.beforeStart ? 1 : 0 );
}
var curval = val();
var snapped = Math.round( curval / ( max - min ) * 100 );
handle
.addClass( "ui-slider-handle-snapping" )
.css( "left", snapped + "%" )
.animationComplete( function() {
handle.removeClass( "ui-slider-handle-snapping" );
});
}
return false;
}
});
slider.insertAfter( control );
// NOTE force focus on handle
this.handle
.bind( "vmousedown", function() {
$( this ).focus();
//check cashier slider checkboxes off
$('#addchips_min').removeClass('pool_checkbox_checked').addClass('pool_checkbox');
$('#addchips_max').removeClass('pool_checkbox_checked').addClass('pool_checkbox');
$('#addchipsLobby_min').removeClass('pool_checkbox_checked').addClass('pool_checkbox');
$('#addchipsLobby_max').removeClass('pool_checkbox_checked').addClass('pool_checkbox');
})
.bind( "vclick", false );
this.handle
.bind( "keydown", function( event ) {
var index = val();
if ( self.options.disabled ) {
return;
}
// In all cases prevent the default and mark the handle as active
switch ( event.keyCode ) {
case $.mobile.keyCode.HOME:
case $.mobile.keyCode.END:
case $.mobile.keyCode.PAGE_UP:
case $.mobile.keyCode.PAGE_DOWN:
case $.mobile.keyCode.UP:
case $.mobile.keyCode.RIGHT:
case $.mobile.keyCode.DOWN:
case $.mobile.keyCode.LEFT:
event.preventDefault();
if ( !self._keySliding ) {
self._keySliding = true;
$( this ).addClass( "ui-state-active" );
}
break;
}
// move the slider according to the keypress
switch ( event.keyCode ) {
case $.mobile.keyCode.HOME:
self.refresh( min );
break;
case $.mobile.keyCode.END:
self.refresh( max );
break;
case $.mobile.keyCode.PAGE_UP:
case $.mobile.keyCode.UP:
case $.mobile.keyCode.RIGHT:
self.refresh( index + step );
break;
case $.mobile.keyCode.PAGE_DOWN:
case $.mobile.keyCode.DOWN:
case $.mobile.keyCode.LEFT:
self.refresh( index - step );
break;
}
}) // remove active mark
.keyup( function( event ) {
if ( self._keySliding ) {
self._keySliding = false;
$( this ).removeClass( "ui-state-active" );
}
});
this.refresh(undefined, undefined, true);
},
refresh: function( val, isfromControl, preventInputUpdate ) {
if ( this.options.disabled ) { return; }
var control = this.element, percent,
cType = control[0].nodeName.toLowerCase(),
min = cType === "input" ? parseFloat( control.attr( "min" ) ) : 0,
max = cType === "input" ? parseFloat( control.attr( "max" ) ) : control.find( "option" ).length - 1;
sliderOrientation = control.attr( "sliderOrientation") || "horizontal";
if ( typeof val === "object" ) {
var data = val,
// a slight tolerance helped get to the ends of the slider
tol = 8;
if(sliderOrientation == "horizontal"){
if ( !this.dragging || data.pageX < this.slider.offset().left - tol || data.pageX > this.slider.offset().left + this.slider.width() + tol ) {return;}
}
else
{
if ( !this.dragging || data.pageY < this.slider.offset().top - tol || data.pageY > this.slider.offset().top + this.slider.height() + tol ) {return;}
}
if(sliderOrientation == "horizontal")
{
percent = Math.round( ( ( data.pageX - this.slider.offset().left ) / this.slider.width() ) * 100 );
}
else
{
percent = Math.round( ( ( data.pageY - this.slider.offset().top ) / this.slider.height() ) * 100 );
}
} else {
if ( val == null ) {
val = cType === "input" ? parseFloat( control.val() ) : control[0].selectedIndex;
}
percent = ( parseFloat( val ) - min ) / ( max - min ) * 100;
}
if ( isNaN( percent ) ) {
return;
}
if ( percent < 0 ) {
percent = 0;
}
if ( percent > 100 ) {
percent = 100;
}
//var newval = Math.round( ( percent / 100 ) * ( max - min ) ) + min;
// newval needs to support floating point min / max values, and must round to the step value
var newval = (percent / 100) * (max - min) + min;
newval -= (((newval - min) * 100) % (0.01 * 100)) / 100;
//newval = Math.round(newval * 100 + 0.01) / 100;
newval = Utils.formatFloatVal((newval * 100 + 0.01) / 100, false, true);
//$('#pool_balance_cashier').html('Slider value: ' + newval);
if(canvas != null){
if(canvas.width < 560){ //only for iphone
$('#iphone_amountIndicator').html('<br> ' + newval);
$('#slider-bet').hide();
$('#slider-bet .ui-slider-handle').hide();
}else{
$('#iphone_amountIndicator').empty();
$('#slider-bet').show();
}
}
//set div that indicates how much we choose to bet with slider
//$(".amountIndicator").width(percent * 280 / 100);
if(control.attr('id') == 'slider-cashier'){
$("#amountIndicator_settings").width(percent * 280 / 102);
}
else if(control.attr('id') == 'slider-lobby-cashier'){
$("#amountIndicator_lobby").width(percent * 280 / 100);
}
else{
$("#amountIndicator_pool").width(percent * 280 / 100);
}
//set label amount to bet/raise button
//$('#prc_pool_notice').html(' <br><br> ----- Slider value: ' + newval + ' this.id: ' + control.attr( "id" ) + ' ----- <br>');
if(buttons.btns != null){
if(buttons.btns[3].active){
buttons.btns[3].label_amount = GL_CURRENCY_SIGN+newval;
}
else if(buttons.btns[4].active){
buttons.btns[4].label_amount = '€'+newval;
}
}
if ( newval < min ) {
newval = min;
}
if ( newval > max ) {
newval = max;
}
// Flip the stack of the bg colors
if ( percent > 60 && cType === "select" ) {
// TODO: Dead path?
}
if(sliderOrientation == "horizontal")
{
//for slider cahsier -> not to very end of slide panel
if(control.attr('id') != 'slider-bet'){
this.handle.css( "left", percent / 1.3 + "%" );
if(percent > 50){
this.handle.css( "left", percent/1.17 + "%" );
}
}else{
this.handle.css( "left", percent + "%" );
}
}
else
{
this.handle.css( "top", percent + "%" );
}
this.handle.attr( {
"aria-valuenow": cType === "input" ? newval : control.find( "option" ).eq( newval ).attr( "value" ),
"aria-valuetext": cType === "input" ? newval : control.find( "option" ).eq( newval ).text(),
title: newval
});
// add/remove classes for flip toggle switch
if ( cType === "select" ) {
if ( newval === 0 ) {
this.slider.addClass( "ui-slider-switch-a" )
.removeClass( "ui-slider-switch-b" );
} else {
this.slider.addClass( "ui-slider-switch-b" )
.removeClass( "ui-slider-switch-a" );
}
}
if ( !preventInputUpdate ) {
// update control"s value
if ( cType === "input" ) {
control.val( newval );
} else {
control[ 0 ].selectedIndex = newval;
}
if ( !isfromControl ) {
control.trigger( "change" );
}
}
},
enable: function() {
this.element.attr( "disabled", false );
this.slider.removeClass( "ui-disabled" ).attr( "aria-disabled", false );
return this._setOption( "disabled", false );
},
disable: function() {
this.element.attr( "disabled", true );
this.slider.addClass( "ui-disabled" ).attr( "aria-disabled", true );
return this._setOption( "disabled", true );
}
});
//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ){
$( $.mobile.slider.prototype.options.initSelector, e.target )
.not( ":jqmData(role='none'), :jqmData(role='nojs')" )
.slider();
});
})( jQuery );
Have feeling
val = function() {
//$('#pool_balance_cashier').html('Slider value3: ' + parseFloat( control.val() ).toFixed(1));
return cType == "input" ? parseFloat( control.val() ).toFixed(2) : control[0].selectedIndex;
},
something to do with output.
Would appriciate if you help on this one.
Thanks!

The HTML5 data type="number" could be the culprit if that is how the field is being rendered. On iOS, it removes trailing zeros. It's annoying. The typical fix is to just make it a type="text" field.

Related

The useCallBack in react not work as expected

I have a question about useCallBack in react?
In useEffect I fetch data and set listDrawPath to context, first listDrawPath is array null [], after finish set listDrawPath second listDrawPath contains object as expected, but in function onDrawingStart the
listDrawPath is still array null [], althought I have add depedency for useCallBack.
I don't know where I have mistaked, I used correct useCallBack as docs in react.
I use Macbook M1 to build app react native for IOS.
I happy if anyone help me about problem above. Code I show below.
// ~Libraries
import {Canvas, useTouchHandler} from '#shopify/react-native-skia';
import {Box, Factory, Row} from 'native-base';
import React, {useCallback, useEffect, useRef} from 'react';
import styles from './styles';
// ~Redux
import {useSelector} from 'react-redux';
import {selectDrawingSelected} from '~Drawing/Store/selectors';
// ~Utils
import {height} from '~Utils/dimensionUtils';
import {filterListByIds} from '~Utils/listUtils';
import {
findIndexContainPointInPaths,
mapperAttributesToPath,
Path,
} from '~Utils/skiaUtils';
// ~Components
import DrawingMasked from '~Drawing/Components/DrawingMasked';
import {useDrawingContext} from './DrawingContext';
import ToolBarColor from './ToolBarColor';
import ToolBarLine from './ToolBarLine';
// ~Constants
import {WIDTH_DRAWING} from '~Drawing/Configs/constants';
const CanvasFactory = Factory(Canvas);
const Drawing = () => {
const drawingSelected = useSelector(selectDrawingSelected);
const PointRef = useRef({x: 0, y: 0});
const lengthPathPrevious = useRef(0);
const drawIndexCurrent = useRef(-1);
const isDrawing = useRef(false);
const {
listCompletedPath,
listDrawPath,
strokeColor,
strokeType,
addCompletedPaths,
addAllDrawPath,
addAllCompletedPath,
updateDrawPath,
changeStrokeType,
changeStrokeColor,
} = useDrawingContext();
useEffect(() => {
if (drawingSelected) {
const newDrawPaths = drawingSelected.drawPaths.map(drawPath => ({
...drawPath,
path: mapperAttributesToPath(drawPath.typeShape, drawPath.attributes),
}));
const newCompletedPaths = drawingSelected.completedPaths.map(
completedPath => ({
...completedPath,
path: mapperAttributesToPath('path', {d: completedPath.path}),
}),
);
addAllDrawPath(newDrawPaths); // I update listDrawPath in here
addAllCompletedPath(newCompletedPaths);
}
}, [drawingSelected, addAllDrawPath, addAllCompletedPath]);
const onDrawingActive = useCallback(
({x, y}) => {
if (!isDrawing.current) return;
if (listCompletedPath.length === lengthPathPrevious.current) {
if (strokeType.strokeCap === 'butt') {
for (
let i = listCompletedPath.length - 1;
i > listCompletedPath.length - 3;
i--
) {
const path = listCompletedPath[i];
path.handleLineTo({
x: x - (listCompletedPath.length - 1 - i) * 10,
y: y - (listCompletedPath.length - 1 - i) * 10,
});
}
} else {
for (
let i = listCompletedPath.length - 1;
i > listCompletedPath.length - 2;
i--
) {
const path = listCompletedPath[i];
path.handleQuadTo(
{
x: PointRef.current.x - (listCompletedPath.length - 1 - i) * 5,
y: PointRef.current.y - (listCompletedPath.length - 1 - i) * 5,
},
{
x: x - (listCompletedPath.length - 1 - i) * 5,
y: y - (listCompletedPath.length - 1 - i) * 5,
},
);
}
}
}
PointRef.current = {x, y};
},
[listCompletedPath, strokeType],
);
console.log(listDrawPath, strokeType, strokeColor); // listDrawPath render 1st is [] and 2st is [object]
const onDrawingStart = useCallback(
({x, y}) => {
// But listDrawPath when use is still null array []
console.log(listDrawPath, strokeType, strokeColor);
drawIndexCurrent.current = findIndexContainPointInPaths(
listDrawPath,
{
x,
y,
},
);
if (drawIndexCurrent.current >= 0) {
const {SvgComponent, svgProperties, ...restStrokeType} =
strokeType;
if (restStrokeType.strokeCap === 'butt') {
const completedPath = new Path(
{x, y},
restStrokeType,
strokeColor,
);
const completedPath2 = new Path(
{x: x - 10, y: y - 10},
restStrokeType,
strokeColor,
);
lengthPathPrevious.current = listCompletedPath.length + 2;
isDrawing.current = true;
addCompletedPaths([completedPath, completedPath2]);
updateDrawPath(drawIndexCurrent.current, [
completedPath.getId(),
completedPath2.getId(),
]);
} else {
const completedPath = new Path(
{x, y},
restStrokeType,
strokeColor,
);
lengthPathPrevious.current = listCompletedPath.length + 1;
isDrawing.current = true;
addCompletedPaths([completedPath]);
updateDrawPath(drawIndexCurrent.current, [completedPath.getId()]);
}
}
PointRef.current = {x, y};
},
[
listDrawPath, // listDrawPath is dependency of useCallback
strokeColor,
strokeType,
listCompletedPath.length,
addCompletedPaths,
updateDrawPath],
);
const onDrawingEnd = useCallback(() => {
isDrawing.current = false;
PointRef.current = {x: 0, y: 0};
}, []);
const touchHandler = useTouchHandler(
{
onActive: onDrawingActive,
onStart: onDrawingStart,
onEnd: onDrawingEnd,
},
[onDrawingActive, onDrawingStart, onDrawingEnd],
);
return (
<Row>
<Box w={`${height}px`} mx={`${(WIDTH_DRAWING - height) / 2}px`}>
<CanvasFactory flex={1} onTouch={touchHandler} style={styles.canvas}>
{listDrawPath.map(drawPath => (
<DrawingMasked
key={drawPath.id}
drawPath={drawPath}
listCompletedPath={filterListByIds(
listCompletedPath,
drawPath.completedPathIds,
)}
/>
))}
</CanvasFactory>
</Box>
<ToolBarColor changeStrokeColor={changeStrokeColor} />
<ToolBarLine
strokeColor={strokeColor}
strokeType={strokeType}
changeStrokeType={changeStrokeType}
/>
</Row>
);
};
export default Drawing;
I want to know where I mistake and why listDrawPath not update in function onDrawingStart

Fixed number of rows per page using pdfmake.js

Defined an own table layouts using pdfmake.js. On print I want per page to contain 7 rows(fixed).I have tried adjusting the height and width of the table cell to contain 7 rows but however if the data in table cell increases the page accumulates with less/more no.of rows.
//layout of the table:
var tablelist={
style: 'tableExample',
table: {
dontBreakRows: true,
widths: [ 20,55,55,55,55,55,55,55,55,55,55,55,55],
headerRows: 1,
body: body
},
layout: {
hLineWidth: function (i, node) {
return (i === 0 || i === node.table.body.length) ? 1 : 1;
},
vLineWidth: function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 1: 1;
},
hLineColor: function (i, node) {
return (i === 0 || i === node.table.body.length) ? 'gray' : 'gray';
},
vLineColor: function (i, node) {
return (i === 0 || i === node.table.widths.length) ? 'gray' : 'gray';
},
},
}
return tablelist;
}
//pushing the table header and other data to the table body
$scope.makePrintTable = function(){
var headers = {
col_1:{ text: 'Day', style: 'tableHeader',rowSpan: 1, alignment: 'center',margin: [0, 8, 0, 0] },
col_2:{ text: 'Date', style: 'tableHeader',rowSpan: 1, alignment: 'center',margin: [0, 8, 0, 0] },
col_3:{ text: '0600-0800', style: 'tableHeader',rowSpan: 1, alignment: 'center',margin: [0, 8, 0, 0] },
.
.
.//Similarly till col_13
col_13:{ text: '1700-1800', style: 'tableHeader',rowSpan: 1, alignment: 'center' ,margin: [0, 8, 0, 0]},
}
body = [];
var row = new Array();
for (var key in headers) {
row.push( headers[key] );
}
body.push(row);
for ( var j=0 ; j< $scope.table.length; j++){
var tableEach={ };
tableEach= $scope.table[j];
/*This for Genarating Object variables*/
for (var i = 1; i < 3; i++) {
window["obj"+i] = new Object();
}
var row = new Array();
var slNoValue = tableEach.slNo;
/*This is for slNo */
obj1["text"] = slNoValue;
obj1["style"]= "cellswidth";
row.push(obj1);
/*This is for Date */
var dateValue = new Date(tableEach.date);
obj2["text"]= dateValue.getDate() + '-' + basicFormats.getMonthName(dateValue.getMonth() )+ '-' + dateValue.getFullYear()+','+ basicFormats.getDayName(dateValue.getDay());
obj2["style"]= "cellswidth";
row.push(obj2);
/*This is for remaining columns (i ranges from 6 to 17 (time in 24hrs clock format) ) */
for(var i=6 ; i<=17 ; i++){
var obj={};
var hourValue = "hour_"+i+"_"+(i+1)+"_value";
var hourValueColor = "hour_"+i+"_"+(i+1)+"_"+"color_value";
hourValue = ( tableEach["hour_"+i] == undefined ? '':(tableEach["hour_"+i]));
hourValueColor =(tableEach["hour_"+i+"_colour"] == undefined ? '#ffffff':(tableEach["hour_"+i+"_colour"]));
obj["text"] = hourValue;
obj["fillColor"] = hourValueColor;
obj["style"] = "cellswidth";
row.push(obj);
console.log(obj);
}
// if( j!= 0 && j % 7 == 0){
// pageBreak : 'before'
// }
}
body.push(row);
}
};
//CSS for tablecells
cellswidth : {
fontSize: 10,
// color:'gray',
bold: true,
alignment: 'center',
margin: [0, 12.55, 0, 12.75],
},
You can use pageBreak function for it:
pageBreakBefore: function(currentNode, followingNodesOnPage, nodesOnNextPage, previousNodesOnPage) {
//Here you can change the criteria according to your requirements
if (currentNode.index % 7 === 0)) {
return true;
}
return false;
},

Google Sheet formula for cumulative sum with condition

I have a Google Sheet with the following layout:
Number | Counted? | Cumulative Total
4 | Y | 4
2 | | 6
9 | Y | 15
... | ... | ...
The first cell in the Cumulative Total column is populated with this formula:
=ArrayFormula((SUMIF(ROW(C2:C1000),"<="&ROW(C2:1000),C2:C1000)
However this counts all rows in the 'Number' column. How can I make the Cumulative Total only count rows where the Counted? cell is Y?
Try this in C2 and copy down:
= N(C1) + A2 * (B2 = "Y")
Update
Doesn't seem to work with SUMIFS, but there is a very slow matrix multiplication alternative:
=ArrayFormula(MMult((Row(2:1000)>=Transpose(Row(2:1000)))*Transpose(A2:A1000*(B2:B1000="Y")), Row(2:1000)^0))
Assuming "Number" in column A and "Counted?" in column B, try in C1
={"SUM"; ArrayFormula(if(ISBLANK(B2:B),,mmult(transpose(if(transpose(row(B2:B))>=row(B2:B), if(B2:B="Y", A2:A,0), 0)),row(B2:B)^0)))}
(Change ranges to suit).
Example
custom formula sample:
=INDEX(IF(B3:B="","", runningTotal(B3:B,1,,A3:A)))
sample file
source code
related
code:
/**
* Get running total for the array of numbers
* by makhrov.max#gmail.com
*
* #param {array} numbers The array of numbers
* #param {number} total_types (1-dafault) sum, (2) avg, (3) min, (4) max, (5) count;
* 1-d array or number
* #param {number} limit number of last values to count next time.
* Set to 0 (defualt) to take all values
* #param {array} keys (optional) array of keys. Function will group result by keys
* #return The hex-code of cell background & font color
* #customfunction
*/
function runningTotal(numbers, total_types, limit, keys) {
// possible types to return
var oTypes = {
'1': 'sum',
'2': 'avg',
'3': 'min',
'4': 'max',
'5': 'count'
}
// checks and defaults
var errPre = '🥴 ';
if( typeof numbers != "object" ) {
numbers = [ [numbers] ];
}
total_types = total_types || [1];
if( typeof total_types != "object" ) {
total_types = [ total_types ];
}
if( keys && typeof keys != "object" ) {
keys = [ [keys] ];
}
if (keys) {
if (numbers.length !== keys.length) {
throw errPre + 'Numbers(' +
numbers.length +
') and keys(' +
keys.length +
') are of different length'; }
}
// assign types
var types = [], type, k;
for (var i = 0; i < total_types.length; i++) {
k = '' + total_types[i];
type = oTypes[k];
if (!type) {
throw errPre + 'Unknown total_type = ' + k;
}
types.push(type);
}
limit = limit || 0;
if (isNaN(limit)) {
throw errPre + '`limit` is not a Number!';
}
limit = parseInt(limit);
// calculating running totals
var result = [],
subres = [],
nodes = {},
key = '-',
val;
var defaultNode_ = {
values: [],
count: 0,
sum: 0,
max: null,
min: null,
avg: null,
maxA: Number.MIN_VALUE,
maxB: Number.MIN_VALUE,
maxC: Number.MIN_VALUE,
minA: Number.MAX_VALUE,
minB: Number.MAX_VALUE,
minC: Number.MAX_VALUE
};
for (var i = 0; i < numbers.length; i++) {
val = numbers[i][0];
// find correct node
if (keys) { key = keys[i][0]; }
node = nodes[key] ||
JSON.parse(JSON.stringify(defaultNode_));
/**
* For findig running Max/Min
* sourse of algorithm
* https://www.geeksforgeeks.org
* /sliding-window-maximum-maximum-of-all-subarrays-of-size-k/
*/
// max
//reset first second and third largest elements
//in response to new incoming elements
if (node.maxA<val) {
node.maxC = node.maxB;
node.maxB = node.maxA;
node.maxA = val;
} else if (node.maxB<val) {
node.maxC = node.maxB;
node.maxB = val;
} else if (node.maxC<val) {
node.maxC = val;
}
// min
if (node.minA>val) {
node.minC = node.minB;
node.minB = node.minA;
node.minA = val;
} else if (node.minB>val) {
node.minC = node.minB;
node.minB = val;
} else if (node.minC>val) {
node.minC = val;
}
// if limit exceeds
if (limit !== 0 && node.count === limit) {
//if the first biggest we earlier found
//is matching from the element that
//needs to be removed from the subarray
if(node.values[0]==node.maxA) {
//reset first biggest to second and second to third
node.maxA = node.maxB;
node.maxB = node.maxC;
node.maxC = Number.MIN_VALUE;
if (val <= node.maxB) {
node.maxC = val;
}
} else if (node.values[0]==node.maxB) {
node.maxB = node.maxC;
node.maxC = Number.MIN_VALUE;
if (val <= node.maxB) {
node.maxC = val;
}
} else if (node.values[0]==node.maxC) {
node.maxC = Number.MIN_VALUE;
if (val <= node.maxB) {
node.maxC = val;
}
} else if(node.values[0]==node.minA) {
//reset first smallest to second and second to third
node.minA = node.minB;
node.minB = node.minC;
node.minC = Number.MAX_VALUE;
if (val > node.minB) {
node.minC = val;
}
}
if (node.values[0]==node.minB) {
node.minB = node.minC;
node.minC = Number.MAX_VALUE;
if (val > node.minB) {
node.minC = val;
}
}
if (node.values[0]==node.minC) {
node.minC = Number.MAX_VALUE;
if (val > node.minB) {
node.minC = val;
}
}
// sum
node.sum -= node.values[0];
// delete first value
node.values.shift();
// start new counter
node.count = limit-1;
}
// add new values
node.count++;
node.values.push(val);
node.sum += val;
node.avg = node.sum/node.count;
node.max = node.maxA;
node.min = node.minA;
// remember entered values for the next loop
nodes[key] = node;
// get the result depending on
// selected total_types
subres = [];
for (var t = 0; t < types.length; t++) {
subres.push(node[types[t]]);
}
result.push(subres);
}
// console.log(JSON.stringify(nodes, null, 4));
return result;
}

jQuerty UI range slider bug after change min value

I have one slider in my page, with this code
<div id="sale-price-range" class="price-range" data-min="200000" data-max="2000000" data-unit="R$" data-min-field="precoMinVenda" data-max-field="precoMaxVenda" data-increment="100000"></div>
My js code is:
// Price Range
$(".price-range").each(function() {
var dataMin = $(this).attr('data-min');
var dataMax = $(this).attr('data-max');
var dataUnit = $(this).attr('data-unit');
var minField = $(this).attr('data-min-field');
var maxField = $(this).attr('data-max-field');
var increment = $(this).attr('data-increment');
$(this).append( "<input type='text' class='first-slider-value' name='"+minField+"' val=''/><input type='text' class='second-slider-value' name='"+maxField+"'/>" );
$(this).slider({
range: true,
min: 0,
max: dataMax,
step: increment,
values: [ dataMin, dataMax ],
slide: function( event, ui ) {
event = event;
if(ui.value < dataMin) {
return false;
}
$(this).find( ".first-slider-value" ).val( dataUnit + " " + ui.values[ 0 ].toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1.") );
$(this).find( ".second-slider-value" ).val( dataUnit + " " + ui.values[ 1 ].toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1.") );
},
stop: function(event,ui) {
if(ui.value >= dataMin) {
postAjaxSearch();
}
}
});
$(this).find( ".first-slider-value" ).val( dataUnit + " " + $( this ).slider( "values", 0 ).toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1.") );
$(this).find( ".second-slider-value" ).val( dataUnit + " " + $( this ).slider( "values", 1 ).toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1.") );
});
It works very well, but if I try to change
min: 0,
To
min: dataMin,
My slider stop to work (I can't drag it). It continues to call postAjaxSearch();, but it doesn't change max/min value neither move the slider-handle.
Why do I need to change min to dataMin?
Because my slider start from 0, but the slider-handle move from dataMin from dataMax. The range betweem dataMin and 0 is on page, but can't move there. I don't want this, the slider should start from dataMin.
Work, but with this space on left (min: 0)
No space, but doesn't work (min: dataMin)
I had the same exact problem, I solved it by using parseInt() on the min value
$("#price-slider").slider({
range: true,
min: parseInt(price_min),
max: price_max,
values: [price_min, price_max],
slide: function (event, ui) {
$("#amount").val("$" + ui.values[0] + " - $" + ui.values[1]);
}
});
I have no idea why this works, it would seem logical that both extremes would work the same but apparently they don't.

Angular Directive to replace html not working on iOS

I have this piece of code:
(function() {
"use strict";
angular
.module("Default")
.directive(
"numberToTime",
["$rootScope", "$compile", "$log",
function($rootScope, $compile, $log) {
return {
"restrict": "A",
"transclude": true,
"replace": true,
"scope": {
"time": "="
},
"link": function(scope, ele, attrs) {
/**
* Function to add one serie of string to another untill complete
* certain length
*
*/
var _lpad = function(str, padString, length) {
while (str.length < length) {
str = padString + str;
}
return str;
};
/**
* Function to turn a number into time format
*/
var _2time = function(s, hideDays, hideSeconds) {
var d = Math.floor(s / (24 * 60 * 60));
s -= d * (24 * 60 * 60);
var h = Math.floor(s / (60 * 60));
s -= h * (60 * 60);
var m = Math.floor(s / 60);
s -= m * 60;
s = Math.floor(s);
var time = "";
if (!hideDays) {
time += d > 0 ? d + " day" + (d > 1 ? "s" : "") + ", " : "";
}
time += _lpad(h.toString(), '0', 2) + ":" + _lpad(m.toString(), '0', 2) + (hideSeconds ? "" : (":" + _lpad(s.toString(), '0', 2)));
return time;
};
var _setTime = function(time) {
var _time = _2time(time, attrs.hidedays != "false", attrs.hideseconds != "false");
ele.html(_time);
};
scope.$watch("time", function() {
_setTime(scope.time);
}, true);
}
};
}
]
)
;
})();
It works ok, if I have something like:
<span number-to-time time="time"></span>
where
$scope.time = 1234;
It turns that number into readable time format. However, in iOS it does not updates the html.
I have it in a player, and if I log the html() content of ele, it says it has the correct time, but in the page I still see 00:00:00, and the time does not updates correctly. What am I doing wrong?
FIXING
Instead of using .html use .text:
ele.text(_time);
Looks like your page is not being rendered. Instead of using html, use text.
var _setTime = function(time) {
var _time = _2time(time, attrs.hidedays != "false", attrs.hideseconds != "false");
ele.text(_time);
};
You can find more information here: http://bit.ly/1E4cMxG

Resources