http://jsfiddle.net/2e7gq/633/
I am trying to create a slider that will display 3 html input boxes.
Quantity
Price per unit
Total (quantity*price per unit)
the goal is to change var price per unit when the slider slides to increments of 50.
thanks!
I am new to programming here is my code:
`$(function() {
var inputValue = $(".mpd_value").val();
$( ".mpq_slider" ).slider({
min:50,
max:50000,
step:50,
value:50,
slide:function(event,ui){
$(".mpd_value").val(ui.value);
$(function(){
calculate();
});
}
});
$(".mpq_value").val($(".mpq_slider").slider("value"));
$(".mpq_value").change(function(event){
$(".mpq_slider").slider("option","value",inputValue);
})
function calculate(){
var quantity = $(".mpd_value").val();
var ppu = .84;
var total = quantity*ppu
$("#total").val(total);
$("#ppu").val(ppu);
};
});
It seems that you're missing a <div class="mpq_slider"></div>. Put it as the first line in the HTML spot. This is the part that makes room for the actual slider. Also, if I understand what you are trying to do correctly, you want the Quantity to increase with the slider and the ppu to change also (like things gets cheaper the more you buy)? If so, you are using the switch statement incorrectly. You could, instead do something with ifs and else ifs:
var ppu = defaultValue;
if (quantity <= 50) {
ppu = 1.117;
}
else if (quantity <= 75) {
ppu = .941;
}
...
Also note how I changed the >= into <=, since that'll make the program check in the right order. Here's what I changed to your code http://jsfiddle.net/2e7gq/637/ .
Now that I think about it, there's another way too. Y&ou can keep the switch if it says switch(true){ and then change all the >=s into <=s.
Glad to hear you're learning Javascript!
Related
I am trying to add columnSummary to my table using Handsontable. But it seems that the function does not fire. The stretchH value gets set and is set properly. But it does not react to the columnSummary option:
this.$refs.hot.hotInstance.updateSettings({stretchH: 'all',columnSummary: [
{
destinationRow: 0,
destinationColumn: 2,
reversedRowCoords: true,
type: 'custom',
customFunction: function(endpoint) {
console.log("TEST");
}
}]
}, false);
I have also tried with type:'sum' without any luck.
Thanks for all help and guidance!
columnSummary cannot be changed with updateSettings: GH #3597
You can set columnSummary settings at the initialization of Handsontable.
One workaround would be to somehow manage your own column summary, since Handsontable one could give you some headeache. So you may try to add one additional row to put your arithmetic in, but it is messy (it needs fixed rows number and does not work with filtering and sorting operations. Still, it could work well under some circumstances.
In my humble opinion though, a summary column has to be fully functionnal. We then need to set our summary row out of the table data. What comes to mind is to take the above mentioned additional row and take it away from the table data "area" but it would force us to make that out of the table row always looks like it still was in the table.
So I thought that instead of having a new line we could just have to add our column summary within column header:
Here is a working JSFiddle example.
Once the Handsontable table is rendered, we need to iterate through the columns and set our column summary right in the table cell HTML content:
for(var i=0;i<tableConfig.columns.length;i++) {
var columnHeader = document.querySelectorAll('.ht_clone_top th')[i];
if(columnHeader) { // Just to be sure column header exists
var summaryColumnHeader = document.createElement('div');
summaryColumnHeader.className = 'custom-column-summary';
columnHeader.appendChild( summaryColumnHeader );
}
}
Now that our placeholders are set, we have to update them with some arithmetic results:
var printedData = hotInstance.getData();
for(var i=0;i<tableConfig.columns.length;i++) {
var summaryColumnHeader = document.querySelectorAll('.ht_clone_top th')[i].querySelector('.custom-column-summary'); // Get back our column summary for each column
if(summaryColumnHeader) {
var res = 0;
printedData.forEach(function(row) { res += row[i] }); // Count all data that are stored under that column
summaryColumnHeader.innerText = '= '+ res;
}
}
This piece of code function may be called anytime it should be:
var hotInstance = new Handsontable(/* ... */);
setMySummaryHeaderCalc(); // When Handsontable table is printed
Handsontable.hooks.add('afterFilter', function(conditionsStack) { // When Handsontable table is filtered
setMySummaryHeaderCalc();
}, hotInstance);
Feel free to comment, I could improve my answer.
in the following code (jsbin available here) I have two input elements, a range and a text, bound together via a computed property.
var vm = new Vue({
el: '#main-container',
data: {
sliderValue: 100,
},
computed: {
actualValue: {
get: function() {
if (this.sliderValue <= 100) {
return this.sliderValue;
} else {
return Math.round(this.sliderValue * 12.5 - 1150);
}
},
/* set won't work for val > 100*/
set: function(val) {
if (val <= 100) {
this.sliderValue = val;
} else {
this.sliderValue = Math.round((val + 1150)/12.5);
}
}
}
},
methods: {
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<div id="main-container">
<input type="range" v-model="sliderValue" min=1 max=132>
<input type="text" v-model="actualValue">
<p>Slider: {{sliderValue}}</p>
<p>Actual: {{actualValue}}</p>
</div>
The range goes from 1 to 132, and its range is mapped [1..500] in the text input, with a simple transformation (basically it's a linear mapping with two different slopes for [1..100] and [101..132]) using the actualValue computed property.
Getting actualValue works as expected: dragging the slider correctly updates the input text with appropriate values in the range [1..500].
I'm not able to find a way to set actualValue, though. I'd like to be able to type a value in the text input, and make the slider's thumb update accordingly to the inverse transformation (val + 1150)/12.5.
It works as long as the typed number is in the range [1..100], but it "explodes" for numbers >100, e.g. 101 makes the sliderValue jump at 80892 and actualValue is then re-calculated as 1010000. As far as I understand, it's a looping-feedback scenario.
I've tried also alternative approaches (watch; v-on:change in the text input; using a third variable) to no avail.
Thanks in advance for any suggestion!
It's an amazing puzzle, and challenged me for a long time!
Look at the screenshot below. Your sliderValue and actualValue are strings, not integers. When you set actualValue as 101, you are actually setting it as a string value of "101"
Now, your sliderValue = ((actualValue + 1150)/12.5)
"101" + 1150 = "1011150" (another string!, try it in the developer console)
That messes up your entire calculation. Now you know how to fix it :-)
And you need to get that Vue devtools from here: https://github.com/vuejs/vue-devtools
EDIT: Response to comment #3
Here is the modified jsBin: http://jsbin.com/mahejozeye/1/edit?html,js,output
The only difference is introduction of two console.log statements in your map2 function. This helps you identify if your non-linear mapping function is working correctly or not. If you keep your developer console open, you will see what is happening in this function.
Case 1: When you set the value radius = 25 using the text box, your sliderRadius gets set to 111.55518394648828 and your radius again gets re-calculated as 25. So it comes around in a full circle and everything is stable here.
Case 2: When you set the value radius = 55, your sliderRadius gets set to 173.03607214428857 through your non-linear map2() function, which resets radius to 51.29869180420927
Clearly there is a circular dependency issue. Your sliderRadius and radius are very much dependent on each other and therefore radius is unable to take the value between 51 and 58.
You need to evaluate why it happens, as it has a lot to do with the non-linear mapping function that you have defined. The moment radius can take stable values at 55 (through the map2 function), then your current problem will be resolved.
The simplest fix is to set your input type to number:
<input type="number" v-model="actualValue">
or you can convert your value to an integer with something like:
set: function(val) {
var intVal = parseInt(val, 10);
if (!isNaN(intVal)) {
if (intVal <= 100) {
this.sliderValue = Math.max(1, intVal);
} else {
this.sliderValue = Math.min(132, Math.round((intVal + 1150) / 12.5));
}
}
}
I am creating a dashboard in DC.js. One of the visualizations is a survival curve showing the percentage of survival on the y-axis and the time in weeks on the x-axis
Each record in the dataset contains a deathAfter column called recidiefNa. This shows the number of weeks after death occurred, and shows -99 for survival.
See sketches for example dataset and desired chart form:
I created this code to create the dimensions and groups and draw the desired chart.
var recDim = cf1.dimension(dc.pluck('recidiefNa'));//sets dimension
var recGroup = recDim.group().reduceCount();
var resDim = cf1.dimension(dc.pluck('residuNa'));
var resGroup = resDim.group().reduceCount();
var scChart = dc.compositeChart("#scStepChart");
scChart
.width(600)
.height(400)
.x(d3.scale.linear().domain([0,52]))
.y(d3.scale.linear().domain([0,100]))
.clipPadding(10)
.brushOn(false)
.xAxisLabel("tijd in weken")
.yAxisLabel("percentage vrij van residu/recidief")
.compose([
dc.lineChart(scChart)
.dimension(recDim)
.group(recGroup)
.interpolate("step-after")
.renderDataPoints(true)
.renderTitle(true)
.keyAccessor(function(d){return d.key;})
.valueAccessor(function(d){return (d.value/cf1.groupAll().reduceCount().value()*100);}),
dc.lineChart(scChart)
.dimension(resDim)
.group(resGroup)
.interpolate("step-after")
.renderDataPoints(true)
.colors(['orange'])
.renderTitle(true)
.keyAccessor(function(d){return d.key;})
.valueAccessor(function(d){return (d.value/cf1.groupAll().reduceCount().value()*100 );})
])
.xAxis().ticks(4);
scChart.render();
This gives the following result:
As you can see my first problem is that I need the line to extend until the y-axis showing x=0weeks and y=100% as the first datapoint.
So that's question number one: is there a way to get that line to look more like my sketch(starting on the y-axis at 100%?
My second and bigger problem is that it is showing the inverse of the percentage I need (eg. 38 instead of 62). This is because of the way the data is structured (which is somehting i rather not change)
First I tried changing the valueaccessor to 100-*calculated number. Which is obviously the normal way to solve this issue. However my result was this:
As you can see now the survival curve is a positive incline which is never possible in a survival curve. This is my second question. Any ideas how to fix this?
Ah, it wasn't clear from the particular example that each data point should be based on the last, but your comment makes that clear. It sounds like what you are looking for is a kind of cumulative sum - in your case, a cumulative subtraction.
There is an entry in the FAQ for this.
Adapting that code to your use case:
function accumulate_subtract_from_100_group(source_group) {
return {
all:function () {
var cumulate = 100;
return source_group.all().map(function(d) {
cumulate -= d.value;
return {key:d.key, value:cumulate};
});
}
};
}
Use it like this:
var decayRecGroup = accumulate_subtract_from_100_group(recGroup)
// ...
dc.lineChart(scChart)
// ...
.group(decayRecGroup)
and similarly for the resGroup
While we're at it, we can concatenate the data to the initial point, to answer your first question:
function accumulate_subtract_from_100_and_prepend_start_point_group(source_group) {
return {
all:function () {
var cumulate = 100;
return [{key: 0, value: cumulate}]
.concat(source_group.all().map(function(d) {
cumulate -= d.value;
return {key:d.key, value:cumulate};
}));
}
};
}
(ridiculous function name for exposition only!)
EDIT: here is #Erik's final adapted answer with the percentage conversion built in, and a couple of performance improvements:
function fakeGrouper(source_group) {
var groupAll = cf1.groupAll().reduceCount();
return {
all:function () {
var cumulate = 100;
var total = groupAll.value();
return [{key: 0, value: cumulate}]
.concat(source_group.all().map(function(d) {
if(d.key > 0) {
cumulate -= (d.value/total*100).toFixed(0);
}
return {key:d.key, value:cumulate};
}));
}
};
}
I have a special case when I want to do something like
let predicate = NSPredicate(format:"
DISTANCE(\(UserLocation),photoLocation) <= visibleRadius AND
DISTANCE(\(UserLocation),photoLocation" <= 10)"
var query = PFQuery(className:"Photo", predicate:predicate)
Basically, I want to get all photos that are taken within 10km around my current location if my current location is also within the photo's visible radius
Also, photoLocation and visibleRadius are two columns in the database, I will supply UserLocation as a PFGeoPoint.
Is it possible to achieve this? In my opinion, I don't think that I may call, for example, photoLocation.latitude to get a specific coordinate value. May I?
I'll appreciate you a lot if this can be achieved!!
I found this at the pares.com docs here is the link
let swOfSF = PFGeoPoint(latitude:37.708813, longitude:-122.526398)
let neOfSF = PFGeoPoint(latitude:37.822802, longitude:-122.373962)
var query = PFQuery(className:"PizzaPlaceObject")
query.whereKey("location", withinGeoBoxFromSouthwest:swOfSF, toNortheast:neOfSF)
var pizzaPlacesInSF = query.findObjects()
This code fetch you all the objects that are in a rectangle area defined by the swOfSF & neOfSF objectc, where seOfSF is in the south-west corner and neOfSF is in the north-east corner.
You can make some alterations to the code and get all the objects in rectangle area that your object is in middle
i would recommend that you don't use a radius, because it will take a lot of calculations. Instead use a rectangle area (like in the code i gave you).
just calculate what is the max/min longitude & max/min latitude from your position and fetch all the objects that are in between. you can read about how to fine the min/max longitude & latitude here Link
I managed to solve it using Parse Cloud Code, here is the quick tutorial
Parse.Cloud.define("latestPosts", function(request, response) {
var limit = 20;
var query = new Parse.Query("Post");
var userLocation = request.params.userLocation;
var searchScope = request.params.searchScope;
var afterDate = request.params.afterDate;
var senderUserName = request.params.senderUserName;
query.withinKilometers("Location", userLocation, searchScope);
query.greaterThan("createdAt", afterDate);
query.notEqualTo("senderUserName",senderUserName);
query.ascending("createdAt");
query.find({
success: function(results) {
var finalResults = results.filter(function(el) {
var visibleRadius = el.get("VisibleRadius");
var postLocation = el.get("Location");
return postLocation.kilometersTo(userLocation) <= visibleRadius;
});
if (finalResults.length > limit) {
var slicedFinalResults = results.slice(0, 20);
response.success(slicedFinalResults);
} else {
response.success(finalResults);
}
},
error: function() {
response.error("no new post");
}
});
});
The code above illustrate a basic example of how to use Cloud Code. Except, I have to make sure that all the returned image are in the union of user's search scope and photo's visible circle. There are more techniques such as Promises. But for my purpose, the code above should just suffice.
I have a form that accepts currency from several fields and depending on what I enter into one, it calculates others. For this most part the code below works (example being the invoice amount field)
<xp:inputText value="#{FInvoiceDoc.InvoiceAmount}" id="InvoiceAmount">
<xp:this.converter>
<xp:convertNumber type="currency"></xp:convertNumber></xp:this.converter>
<xp:eventHandler event="onchange" submit="false" id="eventHandler5">
<xp:this.script><![CDATA[var rate = XSP.getElementById("#{id:ExchangeRate}").value;
var stAmount = XSP.getElementById("#{id:InvoiceAmount}").value;
var stTvat = XSP.getElementById("#{id:TVAT}").value;
var stTst = XSP.getElementById("#{id:TST}").value;
var stToop = XSP.getElementById("#{id:Toop}").value;
var tmp;
// get the dojo currency code
dojo.require("dojo.currency");
// get the numeric values using parse
amount = dojo.currency.parse(stAmount,{currency:"USD"});
total = rate * amount;
XSP.getElementById("#{id:EstUSAmount}").innerHTML = dojo.currency.format(total,{currency:"USD"});
XSP.getElementById("#{id:InvoiceAmount}").value = dojo.currency.format(amount,{currency:"USD"});
if (amount != 0) {
tvat = dojo.currency.parse(stTvat,{currency:"USD"});
tst = dojo.currency.parse(stTst,{currency:"USD"});
toop = dojo.currency.parse(stToop,{currency:"USD"});
tmp = (tvat / (amount-tvat-tst-toop)) * 100;
XSP.getElementById("#{id:VP}").innerHTML = tmp.toFixed(2);
tmp = (tst / (amount-tvat-tst-toop)) * 100;
XSP.getElementById("#{id:STP}").innerHTML = tmp.toFixed(2);
tmp = (toop / (amount-tvat-tst-toop)) * 100;
XSP.getElementById("#{id:OoPP}").innerHTML = tmp.toFixed(2);
}
]]></xp:this.script>
</xp:eventHandler>
</xp:inputText>
Like I said, for the most part this works, but if I enter only a partial number like
200.2
instead of
200.20
then it fails. Most data entry folks will want to not have to key in the last "0" just so it's legal.
btw, if I enter it in as just 200 with no cents, it's OK.
It's as if the statement;
amount = dojo.currency.parse(stAmount,{currency:"USD"});
requires a 2 digit penny amount or no pennys, but doesn't like just the leading cents digit.
Any way around this?
The currency format is very restrictive and needs the certain number of decimal places for a given currency. As you can see here there can be different number of decimal places depending on currency. For most currencies it needs two decimal places though. But, you can trick the parser. Just try it with standard number of decimal places and if it fails try it with one decimal place again. Your code would look like this then:
var amount = dojo.currency.parse(stAmount,{currency:"USD"});
if (!amount && amount!==0) {
amount = dojo.currency.parse(stAmount,{currency:"USD",places:"1"});
}
This accepts inputs like
12
12.3
12.34
$12
$12.3
$12.34
But it is still very picky. It doesn't accept spaces or more decimal places then currency allows.
If you want more flexibility for your users and need USD currency only I'd go for dojo.number or other number parsing instead and show the "$" outside the input field. Then, you'd be able to accept much more formats and could add functions like rounding.
Yeah, I've played with the converters. Thing is I want the converter to stay "Currency". The data I receive from the notes database is always correct and formats properly. Its the manipulation that I''m having a problem with. Since this is all on the client side, I've created a function that I can reuse throughout the page.
<script>
function isNumeric(n) {
n = parseFloat(n);
return !isNaN(n) || n != n;
}
// We call this if its a currency amount. If they only entered one number after
// the decimal, then we just append a 0. We're expecting a string and we send
// the string back.
function cMask(Amount)
{
if (Amount == "") { return "0.00" }
a = Amount.split(".");
if (a.length == 2)
{
if (a[1] != null)
{
if (a[1].length == 1)
{
Amount = Amount + "0";
}
}
}
// get the dojo currency code
dojo.require("dojo.currency");
b = dojo.currency.parse(Amount,{currency:"USD"});
if (isNumeric(b)) {return Amount} else {return "0.00"}
}
</script>
Then its a matter of just changing the initial variable load line.
var stAmount = cMask(XSP.getElementById("#{id:InvoiceAmount}").value);
Seems to work and I've just taught myself how to create reusable client-side javascript for my page.