So basically I have this script (credits to 1stwebdesigner.com and geocodezip) which calculates the distance between 4 locations.
Location 1, location 2, location 3, location 4.
I now need to calculate the distance between location2 and location 3.
and also get that distance and display it and display a price according to this formula
0-10kms = $99,
11-20kms plus $5 per each additional km,
21 - 35kms plus $3.75 per each additional km,
36kms+ plus $3.50 per each additional km,
How do I go about this?
So far I have this (Credits to Rajaprabhu)
(Price Calculation based on the distance covered)
, problem 1 is, the formula is wrong for my situation and problem 2 is the formula isn't getting the distance from the previous calculation.
var request = {
origin:location2,
destination:location3,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status)
{
if (status == google.maps.DirectionsStatus.OK)
{
var distance = response.routes[0].legs[0].distance.text;
var duration = response.routes[0].legs[0].duration.text;
var dvDistance = document.getElementById("dvDistance");
dvDistance.innerHTML = "";
dvDistance.innerHTML += "The one way Distance is: " + distance + "<br />";
dvDistance.innerHTML += "The one way Duration is: " + duration;
//calculate the one way price using the klms
var kms = distance;
var price_1 = (kms > 0) ? 3 : 0; kms = (kms > 0)? kms - 1 : 0;
var price_2 = (kms - 14) > 0 ? (14 * 1.60) : (kms * 1.60); kms = (kms-14)>0 ? kms - 14 : 0;
var price_3 = (kms - 15) > 0 ? (15 * 1.40) : (kms * 1.40); kms = (kms-15)>0 ? kms - 15 : 0;
var price_4 = (kms > 0) ? (kms * 1.20) : 0;
document.getElementById("displayprice").innerHTML = "the one way price is: " + (price_1 + price_2 + price_3 + price_4);
}
});
Stuck on the formula now.
1. anything over 35km gives a incorrect result.
2. 10km and under should really default to $99.
//calculate the one way price using the klms
var kms = distance;
console.log(kms);
var price_1 = (kms > 0) ? 99 : 0; kms = (kms > 0)? kms - 10 : 0;
var price_2 = (kms - 10) > 0 ? (10 * 5.00) : (kms * 5.00); kms = (kms-10)>0 ? kms - 10 : 0;
var price_3 = (kms - 20) > 0 ? (15 * 3.75) : (kms * 3.75); kms = (kms-20)>0 ? kms - 20 : 0;
var price_4 = (kms > 0) ? (kms * 3.50) : 0;
From the documentation:
google.maps.Distance object specification
A representation of distance as a numeric value and a display string.
Properties
text | Type: string | A string representation of the distance value, using the UnitSystem specified in the request.
value | Type: number | The distance in meters.
Your distance is a string: var distance = response.routes[0].legs[0].distance.text;
You should use the numeric value (in meters):
var distance = response.routes[0].legs[0].distance.value/1000;
proof of concept fiddle
code snippet:
var geocoder;
var map;
// New York, NY, USA (40.7127837, -74.00594130000002)
// Newark, NJ, USA (40.735657, -74.1723667)
// Philadelphia, PA, USA (39.9525839, -75.16522150000003)
// Baltimore, MD, USA (39.2903848, -76.61218930000001)
var location1 = new google.maps.LatLng(40.7127837, -74.005941);
var location2 = new google.maps.LatLng(40.735657, -74.1723667);
var location3 = new google.maps.LatLng(39.9525839, -75.1652215);
var location4 = new google.maps.LatLng(39.2903848, -76.6121893);
function initialize() {
// create a new map object
// set the div id where it will be shown
// set the map options
var mapOptions = {
center: {
lat: 42,
lng: -72
},
zoom: 4
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
// show route between the points
directionsService = new google.maps.DirectionsService();
directionsDisplay = new google.maps.DirectionsRenderer({
suppressMarkers: true,
suppressInfoWindows: true
});
directionsDisplay.setMap(map);
var request = {
origin: location1,
waypoints: [{
location: location2,
}, {
location: location3,
}],
destination: location4,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
var route = response.routes[0];
var summaryPanel = document.getElementById("directions_panel");
summaryPanel.innerHTML = "";
// For each route, display summary information.
for (var i = 0; i < route.legs.length; i++) {
var routeSegment = i + 1;
summaryPanel.innerHTML += "<b>Route Segment: " + routeSegment + "</b><br />";
summaryPanel.innerHTML += route.legs[i].start_address + " to ";
summaryPanel.innerHTML += route.legs[i].end_address + "<br />";
summaryPanel.innerHTML += route.legs[i].distance.text + "<br />";
summaryPanel.innerHTML += route.legs[i].duration.text + "<br />";
}
computeTotalDistance(response);
var request = {
origin: location2,
destination: location3,
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
if (status == google.maps.DirectionsStatus.OK) {
var distance = response.routes[0].legs[0].distance.value / 1000;
var duration = response.routes[0].legs[0].duration.text;
var dvDistance = document.getElementById("dvDistance");
dvDistance.innerHTML = "";
dvDistance.innerHTML += "The one way Distance (segment 2) is: " + distance + "<br />";
dvDistance.innerHTML += "The one way Duration (segment 2) is: " + duration;
//calculate the one way price using the klms
var kms = distance;
console.log(kms);
var price_1 = (kms > 0) ? 3 : 0;
kms = (kms > 0) ? kms - 1 : 0;
var price_2 = (kms - 14) > 0 ? (14 * 1.60) : (kms * 1.60);
kms = (kms - 14) > 0 ? kms - 14 : 0;
var price_3 = (kms - 15) > 0 ? (15 * 1.40) : (kms * 1.40);
kms = (kms - 15) > 0 ? kms - 15 : 0;
var price_4 = (kms > 0) ? (kms * 1.20) : 0;
document.getElementById("displayprice").innerHTML = "the one way price (segment 2) is: $" + (price_1 + price_2 + price_3 + price_4).toFixed(2);
}
});
} else {
alert("directions response " + status);
}
});
}
google.maps.event.addDomListener(window, "load", initialize);
function computeTotalDistance(result) {
var totalDist = 0;
var totalTime = 0;
var myroute = result.routes[0];
for (i = 0; i < myroute.legs.length; i++) {
totalDist += myroute.legs[i].distance.value;
totalTime += myroute.legs[i].duration.value;
}
totalDist = totalDist / 1000.
document.getElementById("total").innerHTML = "total distance is: " + totalDist + " km<br>total time is: " + (totalTime / 60).toFixed(2) + " minutes<br>total price is: $" + ((totalTime / 60).toFixed(2) * 2.1) + " dollars<br>saturday price is: $" + ((totalTime / 60).toFixed(2) * 2.35) + " dollars<br>sunday price is: $" + ((totalTime / 60).toFixed(2) * 2.6) + " dollars";
}
html,
body,
#map_canvas {
height: 100%;
width: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"></script>
<div id="map_canvas"></div>
<div id="dvDistance"></div>
<div id="displayprice"></div>
<div id="total"></div>
<div id="directions_panel"></div>
Related
Currently, our application uses Here Map Attributes API v7 and the response looks like this
https://pde.api.here.com/1/index.json?app_id=&app_code=&layer=ROAD_GEOM_FCn&attributes=LINK_ID&values=17339738,17339811
{
"Layers":
[
{
"layer": "ROAD_GEOM_FC3",
"level": 11,
"tileXYs":
[
{
"x": 2000,
"y": 1611
},
{
"x": 2009,
"y": 1611
}
]
}
]
}
We're trying to migrate to new V8 API and having issues with translating the response model. In v8 the response returns tileIds (instead of tileXYs)
https://smap.hereapi.com/v8/maps/index.json?layer=ROAD_GEOM_FCn&attributes=LINK_ID&values=17339738,17339811&apiKey=
{
"Layers":
[
{
"layer": "ROAD_GEOM_FC3",
"level": 11,
"tileIDs":
[
6600656,
6600665
]
}
]
}
Is there a way I can convert tileIds into tileXYs similar to the legacy response?
I tried to convert lat and long from this API endpoint like in the docs but didn't work.
https://developer.here.com/documentation/content-map-attributes/dev_guide/topics/here-map-content.html
https://smap.hereapi.com/v8/maps/attributes.json?layers=ROAD_GEOM_FC3&in=tile:6600656&apikey=
First variant:
Calculates tileX and tileY out of a given tileId and a level
#param tileId - the tile id
#param level - the PDE layer level
#param tileXYLevel - this OUT parameter is filed with tileX, tileY and the level
*/
public void getTileXYLevel(long tileId, int level, int tileXYLevel[]) throws Exception
{
if (isStaticContent) {
tileXYLevel[0] = 0;
tileXYLevel[1] = 0;
tileXYLevel[2] = 0;
return;
}
int numTilesVertical = 1L << level;
int tileX = (int)(tileId % (2 * numTilesVertical));
if (tileX < 0 || tileX >= numTilesVertical * 2)
throw new Exception("Invalid tileX=" + tileX + " for level " + level + ", must be [0 ... " + (numTilesVertical * 2 - 1) + "]");
int tileY = (int)((tileId - tileX) / (2 * numTilesVertical));
if (tileY < 0 || tileY >= numTilesVertical)
throw new Exception("Invalid tileY=" + tileY + " for level " + level + ", must be [0 ... " + (numTilesVertical - 1) + "]");
tileXYLevel[0] = tileX;
tileXYLevel[1] = tileY;
tileXYLevel[2] = level;
}
Second variant:
Regarding this formulas:
tile size = 180° / 2^level [degree]
tileY = trunc((latitude + 90°) / tile size)
tileX = trunc((longitude + 180°) / tile size)
tileID = tileY * 2 * (2^level) + tileX
This is not possible. At least it is needed to know whether latitude or longitude then you can calculate tileX or tileY.
Better way is:
1.Request this https://smap.hereapi.com/v8/maps/attributes.json?layers=ROAD_GEOM_FC3&in=tile:6600656&apikey=
In fist Row of response you have:
Meta: {
layerName: "ROAD_GEOM_FC3",
tileId: 6600656,
level: 11,
mapRegion: "WEU",
mapRelease: "22125",
},
Rows: [
{
LINK_ID: "17339811",
LONG_HAUL: "N",
NAME: "B4304",
NAMES: "ENGBNB4304",
TUNNEL: "N",
BRIDGE: "N",
LAT: "5167314,16,9,10",
LON: "-417072,-9,-6,-9",
ZLEVEL: ",,,",
ELEVATION: ",,,",
TOPOLOGY_ID: "98996232",
START_OFFSET: "0",
}
Then you have from LAT, LON:
lat: 51.67314; lng: -4.17072
2.From above coordinate you calculate tileX and tileY, see please Javascript example:
var
degSize = 180 / Math.pow(2, level),
tileY = Math.floor((lat + 90) / degSize),
tileX = Math.floor((lng + 180) / degSize);
You know from response of https://smap.hereapi.com/v8/maps/index.json? that level is 11 (or you know it from "Meta" property)
After calculation we have tileX = 2000 and tileY = 1611
I wrote this script, which works perfectly, except it is taking about 5 minutes (give a few) to run. What would be the best way to speed this up?
Kind regards, Rob
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Start();
int divnumber = 17476;
HtmlAgilityPack.HtmlWeb web = new HtmlAgilityPack.HtmlWeb();
while (divnumber < 18500)
{
string DivUrl = "https://www.hattrick.org/nl/World/Series/?LeagueLevelUnitID=" + divnumber;
HtmlAgilityPack.HtmlDocument doc = web.Load(DivUrl);
var ClassShy = doc.DocumentNode.SelectNodes("//a[#class='shy']");
if (ClassShy != null)
{
ClassShy.ToList();
int i = 0;
foreach (var item in ClassShy)
{
i++;
}
int divForList = divnumber - 17475;
if (i > 4)
{
Console.WriteLine("VI." + divForList + " - " + i);
}
}
divnumber++;
}
sw.Stop();
TimeSpan ts = sw.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}:{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
Console.WriteLine("\nDone in " + elapsedTime);
sw.Reset();
Updates
Updated fiddle to simplify what is going on:
added four buttons to move the stick, each button increments the value by 30 in the direction
plotted x and y axis
red line is the stick, with bottom end coordinates at (ax,ay) and top end coordinates at (bx,by)
green line is (presumably) previous position of the stick, with bottom end coordinates at (ax, ay) and top end coordinates at (bx0, by0)
So, after having my ninja moments. I'm still nowhere near understanding the sorcery behind unknownFunctionA and unknownFunctionB
For the sake of everyone (all two of you) here is what I've sort of learnt so far
function unknownFunctionB(e) {
var t = e.b.x - e.a.x
, n = e.b.y - e.a.y
, a = t * t + n * n;
if (a > 0) {
if (a == e.lengthSq)
return;
var o = Math.sqrt(a)
, i = (o - e.length) / o
, s = .5;
e.b.x -= t * i * .5 * s,
e.b.y -= n * i * .5 * s
}
}
In the unknownFunctionB above, variable o is length of the red sitck.
Still don't understand
What is variable i and how is (bx,by) calculated? essentially:
bx = bx - (bx - ax) * 0.5 * 0.5
by = by - (by - ay) * 0.5 * 0.5
In unknownFunctionA what are those magic numbers 1.825 and 0.825?
Below is irrelevant
I'm trying to deconstruct marker drag animation used on smartypins
I've managed to get the relevant code for marker move animation but I'm struggling to learn how it all works, especially 2 functions (that I've named unknownFunctionA and unknownFunctionB)
Heres the StickModel class used on smartypins website, unminified to best of my knowledge
function unknownFunctionA(e) {
var t = 1.825
, n = .825
, a = t * e.x - n * e.x0
, o = t * e.y - n * e.y0 - 5;
e.x0 = e.x,
e.y0 = e.y,
e.x = a,
e.y = o;
}
function unknownFunctionB(e) {
var t = e.b.x - e.a.x
, n = e.b.y - e.a.y
, a = t * t + n * n;
if (a > 0) {
if (a == e.lengthSq)
return;
var o = Math.sqrt(a)
, i = (o - e.length) / o
, s = .5;
e.b.x -= t * i * .5 * s,
e.b.y -= n * i * .5 * s
}
}
function StickModel() {
this._props = function(e) {
return {
length: e,
lengthSq: e * e,
a: {
x: 0,
y: 0
},
b: {
x: 0,
y: 0 - e,
x0: 0,
y0: 0 - e
},
angle: 0
}
}
(60)
}
var radianToDegrees = 180 / Math.PI;
StickModel.prototype = {
pos: {
x: 0,
y: 0
},
angle: function() {
return this._props.angle
},
reset: function(e, t) {
var n = e - this._props.a.x
, a = t - this._props.a.y;
this._props.a.x += n,
this._props.a.y += a,
this._props.b.x += n,
this._props.b.y += a,
this._props.b.x0 += n,
this._props.b.y0 += a
},
move: function(e, t) {
this._props.a.x = e,
this._props.a.y = t
},
update: function() {
unknownFunctionA(this._props.b),
unknownFunctionB(this._props),
this.pos.x = this._props.a.x,
this.pos.y = this._props.a.y;
var e = this._props.b.x - this._props.a.x
, t = this._props.b.y - this._props.a.y
, o = Math.atan2(t, e);
this._props.angle = o * radianToDegrees;
}
}
StickModel.prototype.constructor = StickModel;
Fiddle link with sample implementation on canvas: http://jsfiddle.net/vff1w82w/3/
Again, Everything works as expected, I'm just really curious to learn the following:
What could be the ideal names for unknownFunctionA and unknownFunctionB and an explanation of their functionality
What are those magic numbers in unknownFunctionA (1.825 and .825) and .5 in unknownFunctionB.
Variable o in unknownFunctionB appears to be hypotenuse. If that's the case, then what exactly is i = (o - e.length) / o in other words, i = (hypotenuse - stickLength) / hypotenuse?
First thing I'd recommend is renaming all those variables and methods until they start making sense. I also removed unused code.
oscillator
adds wobble to the Stick model by creating new position values for the Stick that follows the mouse
Exaggerates its movement by multiplying its new position by 1.825 and also subtracting the position of an "echo" of its previous position multiplied by 0.825. Sort of looking for a middle point between them. Helium makes the stick sit upright.
overshooter minus undershooter must equal 1 or you will have orientation problems with your stick. overshooter values above 2.1 tend to make it never settle.
seekerUpdate
updates the seeker according to mouse positions.
The distance_to_cover variable measures the length of the total movement. You were right: hypothenuse (variable o).
The ratio variable calculates the ratio of the distance that can be covered subtracting the size of the stick. The ratio is then used to limit the adjustment of the update on the seeker in both directions (x and y). That's how much of the update should be applied to prevent overshooting the target.
easing slows down the correct updates.
There are lots of interesting info related to vectors on the book The nature of code.
function oscillator(seeker) {
var overshooter = 1.825;
var undershooter = .825;
var helium = -5;
var new_seeker_x = overshooter * seeker.x - undershooter * seeker.echo_x;
var new_seeker_y = overshooter * seeker.y - undershooter * seeker.echo_y + helium;
seeker.echo_x = seeker.x;
seeker.echo_y = seeker.y;
seeker.x = new_seeker_x;
seeker.y = new_seeker_y;
}
function seekerUpdate(stick) {
var dX = stick.seeker.x - stick.mouse_pos.x;
var dY = stick.seeker.y - stick.mouse_pos.y;
var distance_to_cover = Math.sqrt(dX * dX + dY * dY);
var ratio = (distance_to_cover - stick.length) / distance_to_cover;
var easing = .25;
stick.seeker.x -= dX * ratio * easing;
stick.seeker.y -= dY * ratio * easing;
}
function StickModel() {
this._props = function(length) {
return {
length: length,
lengthSq: length * length,
mouse_pos: {
x: 0,
y: 0
},
seeker: {
x: 0,
y: 0 - length,
echo_x: 0,
echo_y: 0 - length
}
}
}(60)
}
StickModel.prototype = {
move: function(x, y) {
this._props.mouse_pos.x = x;
this._props.mouse_pos.y = y;
},
update: function() {
oscillator(this._props.seeker);
seekerUpdate(this._props);
}
};
StickModel.prototype.constructor = StickModel;
// Canvas to draw stick model coordinates
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
canvas.width = window.outerWidth;
canvas.height = window.outerHeight;
var canvasCenterX = Math.floor(canvas.width / 2);
var canvasCenterY = Math.floor(canvas.height / 2);
context.translate(canvasCenterX, canvasCenterY);
var stickModel = new StickModel();
draw();
setInterval(function() {
stickModel.update();
draw();
}, 16);
$(window).mousemove(function(e) {
var mouseX = (e.pageX - canvasCenterX);
var mouseY = (e.pageY - canvasCenterY);
stickModel.move(mouseX, mouseY);
stickModel.update();
draw();
});
function draw() {
context.clearRect(-canvas.width, -canvas.height, canvas.width * 2, canvas.height * 2);
// red line from (ax, ay) to (bx, by)
context.beginPath();
context.strokeStyle = "#ff0000";
context.moveTo(stickModel._props.mouse_pos.x, stickModel._props.mouse_pos.y);
context.lineTo(stickModel._props.seeker.x, stickModel._props.seeker.y);
context.fillText('mouse_pos x:' + stickModel._props.mouse_pos.x + ' y: ' + stickModel._props.mouse_pos.y, stickModel._props.mouse_pos.x, stickModel._props.mouse_pos.y);
context.fillText('seeker x:' + stickModel._props.seeker.x + ' y: ' + stickModel._props.seeker.y, stickModel._props.seeker.x - 30, stickModel._props.seeker.y);
context.lineWidth = 1;
context.stroke();
context.closePath();
// green line from (ax, ay) to (bx0, by0)
context.beginPath();
context.strokeStyle = "#00ff00";
context.moveTo(stickModel._props.mouse_pos.x, stickModel._props.mouse_pos.y);
context.lineTo(stickModel._props.seeker.echo_x, stickModel._props.seeker.echo_y);
context.fillText('echo x:' + stickModel._props.seeker.echo_x + ' y: ' + stickModel._props.seeker.echo_y, stickModel._props.seeker.echo_x, stickModel._props.seeker.echo_y - 20);
context.lineWidth = 1;
context.stroke();
context.closePath();
// blue line from (bx0, by0) to (bx, by)
context.beginPath();
context.strokeStyle = "#0000ff";
context.moveTo(stickModel._props.seeker.echo_x, stickModel._props.seeker.echo_y);
context.lineTo(stickModel._props.seeker.x, stickModel._props.seeker.y);
context.stroke();
context.closePath();
}
body {
margin: 0px;
padding: 0px;
}
canvas {
display: block;
}
p {
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<p>Move your mouse to see the stick (colored red) follow</p>
<canvas id="myCanvas"></canvas>
I'm using Google Earth plugin in order to show multiple polygons(circles) at the same time, how can I do this?, I have a listbox with lat or geoDataSplit[0] and lng or geoDataSplit[1], Want to go through this listbox latlngs, pass them to polygonplacemark, store all the circles may be in an array or what would you suggest and show all of them, the code below prints all the circles but one by one and not all at the same time:
var setOfPlacemarks = [];
function createCircle(centerLat, centerLng, radius) {
function make2Circle(centerLat, centerLng, radius) {
var ring = ge.createLinearRing('');
var steps = 25;
var pi2 = Math.PI * 2;
for (var i = 0; i < steps; i++) {
var lat = parseFloat(centerLat) + radius * Math.cos(i / steps * pi2);
var lng = centerLng + radius * Math.sin(i / steps * pi2);
ring.getCoordinates().pushLatLngAlt(lat, lng, 0);
}
return ring;
}
var polygonPlacemark = ge.createPlacemark('');
polygonPlacemark.setGeometry(ge.createPolygon(''));
var outer = ge.createLinearRing('');
var dlist = document.getElementById('salesList');
for (var i = 0; i < dlist.options.length; i++) {
var geoData = dlist.options[i].text;
geoDataSplit = geoData.split(",");
polygonPlacemark.getGeometry().setOuterBoundary(make2Circle(parseFloat(geoDataSplit[0]), parseFloat(geoDataSplit[1]), .00001*parseInt(geoDataSplit[2])/5));
polygonPlacemark.setName(geoDataSplit[2]);
ge.getFeatures().appendChild(polygonPlacemark);
setOfPlacemarks.push(polygonPlacemark);
}
printAllPlacemarks();
}
function printAllPlacemarks() {
var kmlObjectList = ge.getFeatures().getChildNodes();
alert(kmlObjectList);
for (var i = 0; i < setOfPlacemarks.length; i++) {
alert(setOfPlacemarks[i]);
ge.getFeatures().appendChild(setOfPlacemarks[i]);
}
}
I have a .net 2.0 ascx control with a start time and end time textboxes. The data is as follows:
txtStart.Text = 09/19/2008 07:00:00
txtEnd.Text = 09/19/2008 05:00:00
I would like to calculate the total time (hours and minutes) in JavaScript then display it in a textbox on the page.
function stringToDate(string) {
var matches;
if (matches = string.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2}) (\d{2,2}):(\d{2,2}):(\d{2,2})$/)) {
return new Date(matches[1], matches[2] - 1, matches[3], matches[4], matches[5], matches[6]);
} else {
return null;
};
}
function getTimeSpan(ticks) {
var d = new Date(ticks);
return {
hour: d.getUTCHours(),
minute: d.getMinutes(),
second: d.getSeconds()
}
}
var beginDate = stringToDate('2008-09-19 07:14:00');
var endDate = stringToDate('2008-09-19 17:35:00');
var sp = getTimeSpan(endDate - beginDate);
alert("timeuse:" + sp.hour + " hour " + sp.minute + " minute " + sp.second + " second ");
you can use getUTCHours() instead Math.floor(n / 3600000);
Once your textbox date formats are known in advance, you can use Matt Kruse's Date functions in Javascript to convert the two to a timestamp, subtract and then write to the resulting text box.
Equally the JQuery Date Input code for stringToDate could be adapted for your purposes - the below takes a string in the format "YYYY-MM-DD" and converts it to a date object. The timestamp (getTime()) of these objects could be used for your calculations.
stringToDate: function(string) {
var matches;
if (matches = string.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2})$/)) {
return new Date(matches[1], matches[2] - 1, matches[3]);
} else {
return null;
};
}
I took what #PConroy did and added to it by doing the calculations for you. I also added the regex to make sure the time is part of the string to create the date object.
<html>
<head>
<script type="text/javascript">
function stringToDate(string) {
var matches;
if (matches = string.match(/^(\d{4,4})-(\d{2,2})-(\d{2,2}) (\d{2,2}):(\d{2,2}):(\d{2,2})$/)) {
return new Date(matches[1], matches[2] - 1, matches[3], matches[4], matches[5], matches[6]);
} else {
return null;
};
}
//Convert duration from milliseconds to 0000:00:00.00 format
function MillisecondsToDuration(n) {
var hms = "";
var dtm = new Date();
dtm.setTime(n);
var h = "000" + Math.floor(n / 3600000);
var m = "0" + dtm.getMinutes();
var s = "0" + dtm.getSeconds();
var cs = "0" + Math.round(dtm.getMilliseconds() / 10);
hms = h.substr(h.length-4) + ":" + m.substr(m.length-2) + ":";
hms += s.substr(s.length-2) + "." + cs.substr(cs.length-2);
return hms;
}
var beginDate = stringToDate('2008-09-19 07:14:00');
var endDate = stringToDate('2008-09-19 17:35:00');
var n = endDate.getTime() - beginDate.getTime();
alert(MillisecondsToDuration(n));
</script>
</head>
<body>
</body>
</html>
This is pretty rough, since I coded it up pretty fast, but it works. I tested it out. The alert box will display 0010:21:00.00 (HHHH:MM:SS.SS). Basically all you need to do is get the values from your text boxes.
The answers above all assume string manipulation. Here's a solution that works with pure date objects:
var start = new Date().getTime();
window.setTimeout(function(){
var diff = new Date(new Date().getTime() - start);
// this will log 0 hours, 0 minutes, 1 second
console.log(diff.getHours(), diff.getMinutes(),diff.getSeconds());
},1000);
I googled for calculating a timespan in javascript and found this question on SO; unfortunately the question text and actual question (only needing hours and minutes) are not the same... so I think I arrived here in error.
I did write an answer to the question title, however - so if anyone else wants something that prints out something like "1 year, and 15 minutes", then this is for you:
function formatTimespan(from, to) {
var text = '',
span = { y: 0, m: 0, d: 0, h: 0, n: 0 };
function calcSpan(n, fnMod) {
while (from < to) {
// Modify the date, and check if the from now exceeds the to:
from = from[fnMod](1);
if (from <= to) {
span[n] += 1;
} else {
from = from[fnMod](-1);
return;
}
}
}
function appendText(n, unit) {
if (n > 0) {
text += ((text.length > 0) ? ', ' : '') +
n.toString(10) + ' ' + unit + ((n === 1) ? '' : 's');
}
}
calcSpan('y', 'addYears');
calcSpan('m', 'addMonths');
calcSpan('d', 'addDays');
calcSpan('h', 'addHours');
calcSpan('n', 'addMinutes');
appendText(span.y, 'year');
appendText(span.m, 'month');
appendText(span.d, 'day');
appendText(span.h, 'hour');
appendText(span.n, 'minute');
if (text.lastIndexOf(',') < 0) {
return text;
}
return text.substring(0, text.lastIndexOf(',')) + ', and' + text.substring(text.lastIndexOf(',') + 1);
}
Use Math.floor(n / 3600000) instead of getUTCHours() or else you would lose the number of hours greater than 24.
For example, if you have 126980000 milliseconds, this should translate to 0035:16:20.00
If you use getUTCHours() you get an incorrect string 0011:16:20.00
Better instead, use this (modifications denoted by KK-MOD):
function MillisecondsToDuration(n) {
var hms = "";
var dtm = new Date();
dtm.setTime(n);
var d = Math.floor(n / 3600000 / 24); // KK-MOD
var h = "0" + (Math.floor(n / 3600000) - (d * 24)); // KK-MOD
var m = "0" + dtm.getMinutes();
var s = "0" + dtm.getSeconds();
var cs = "0" + Math.round(dtm.getMilliseconds() / 10);
hms = (d > 0 ? d + "T" : "") + h.substr(h.length - 2) + ":" + m.substr(m.length - 2) + ":"; // KK-MOD
hms += s.substr(s.length - 2) + "." + cs.substr(cs.length - 2);
return hms; }
So now, 192680000 gets displayed as 1T11:16:20.00 which is 1 day 11 hours 16 minutes and 20 seconds
I like the K3 + KK-MOD approach, but I needed to show negative timespans, so I made the following modifications:
function MillisecondsToDuration(milliseconds) {
var n = Math.abs(milliseconds);
var hms = "";
var dtm = new Date();
dtm.setTime(n);
var d = Math.floor(n / 3600000 / 24); // KK-MOD
var h = "0" + (Math.floor(n / 3600000) - (d * 24)); // KK-MOD
var m = "0" + dtm.getMinutes();
var s = "0" + dtm.getSeconds();
var cs = "0" + Math.round(dtm.getMilliseconds() / 10);
hms = (milliseconds < 0 ? " - " : "");
hms += (d > 0 ? d + "." : "") + h.substr(h.length - 2) + ":" + m.substr(m.length - 2) + ":"; // KK-MOD
hms += s.substr(s.length - 2) + "." + cs.substr(cs.length - 2);
return hms; }
I also changed the 'T' separator to a '.' for my own formatting purposes.
Now a negative value passed in, say -360000 (negative six minutes) will produce the following output:
- 00:06:00