adding a title to marker on map in mapbox also would like to give the marker a name in firebase - geolocation

(function() {
'use strict';
//
// Utilities
//
function guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}
function now() {
return Math.floor(Date.now() / 1000);
}
//
// Environment
//
var myUuid;
var mapId;
mapId = location.hash.replace(/^#/, '');
if (!mapId) {
mapId = (Math.random() + 1).toString(36).substring(2, 12);
location.hash = mapId;
}
if (typeof localStorage == 'undefined') {
document.getElementById('map').innerHTML = 'Sorry but your browser is not supported'
return
}
myUuid = localStorage.getItem('myUuid');
if (!myUuid) {
myUuid = guid();
localStorage.setItem('myUuid', myUuid);
}
//
// Mapbox
//
var map;
var markers = {};
var mapZooming = false;
L.mapbox.accessToken = config.mapbox.accessToken;
map = L.mapbox.map('map', config.mapbox.mapId, {
zoomControl: false,
attributionControl: false,
tileLayer: {
maxNativeZoom: 19
}
}).setView([48.861920, 2.341755], 18)
// map.on('ready', function() { console.log('map.ready') });
// https://github.com/bbecquet/Leaflet.PolylineDecorator
L.RotatedMarker = L.Marker.extend({
options: { angle: 0 },
_setPos: function(pos) {
L.Marker.prototype._setPos.call(this, pos);
if (L.DomUtil.TRANSFORM) {
// use the CSS transform rule if available
this._icon.style[L.DomUtil.TRANSFORM] += ' rotate(' + this.options.angle + 'deg)';
} else if (L.Browser.ie) {
// fallback for IE6, IE7, IE8
var rad = this.options.angle * L.LatLng.DEG_TO_RAD,
costheta = Math.cos(rad),
sintheta = Math.sin(rad);
this._icon.style.filter += ' progid:DXImageTransform.Microsoft.Matrix(sizingMethod=\'auto expand\', M11=' +
costheta + ', M12=' + (-sintheta) + ', M21=' + sintheta + ', M22=' + costheta + ')';
}
}
});
L.rotatedMarker = function(pos, options) {
return new L.RotatedMarker(pos, options);
};
map.on('zoomstart', function() {
mapZooming = true
})
map.on('zoomend', function() {
mapZooming = false
})
function createIcon(uuid, point) {
var color
var svg;
if (uuid === myUuid) {
// Own marker
color = '#2196f3'
} else if (point.timestamp < now() - 60) {
// Inactive marker
color = '#bdbdbd'
} else {
// Others marker
color = '#ff9800'
}
var svg = '<svg width="70" height="70" xmlns="http://www.w3.org/2000/svg">'
+ '<path fill="#fff" d="m35,18.000002c-9.400002,0 -17,7.599995 -17,16.999998s7.599998,17 17,17s17,-7.599998 17,-17s-7.599998,-16.999998 -17,-16.999998zm0,30.999998c-7.700001,0 -14,-6.299999 -14,-14s6.299999,-13.999998 14,-13.999998s14,6.299997 14,13.999998s-6.300003,14 -14,14z"/>'
+ '<circle fill="' + color + '" stroke="null" r="14.031405" cy="35.000002" cx="34.999999"/>'
+ (point.orientation ? '<polygon fill="' + color + '" points="47.699997901916504,16.983383178710938 47.000000953674316,17.68338394165039 35.000000953674316,12.7833890914917 23.00000286102295,17.68338394165039 22.300002098083496,16.983383178710938 35.000000953674316,4.28338623046875" />' : '')
+ '</svg>'
return L.icon({
iconUrl: 'data:image/svg+xml;base64,' + btoa(svg),
iconSize: [40, 40],
})
}
I found this code on Github and im trying to set a name to the marker but I am having trouble doing so can some one point me in the right direction I would like to display a name when you hover over the marker.
function addPoint(uuid, point) {
var marker = L.rotatedMarker([point.coords.latitude, point.coords.longitude], {
//zIndexOffset: (uuid === myUuid ? 1000 : 0),
icon: createIcon(uuid, point)
})
markers[uuid] = marker;
marker.options.angle = point.orientation;
marker.addTo(map)
map.fitBounds(Object.keys(markers).map(function(uuid) {
return markers[uuid].getLatLng()
}))
}
function removePoint(uuid) {
if (markers[uuid]) {
map.removeLayer(markers[uuid])
//markers[uuid] = null
}
}
function updatePoint(uuid, point) {
// Avoid clipping effect when zooming map + updating point at the same time.
if (mapZooming) {
map.once('zoomend', function() {
updatePoint(uuid, point)
})
return
}
var marker = markers[uuid]
marker.setIcon(createIcon(uuid, point));
marker.options.angle = point.orientation
marker.setLatLng([point.coords.latitude, point.coords.longitude])
}
function putPoint(uuid, point) {
if (markers[uuid]) {
updatePoint(uuid, point)
} else {
addPoint(uuid, point)
}
}
In Fire Base instead of some random number and letters I would like to give the markers names
//
// Firebase
//
var endpoint;
endpoint = new Firebase('https://' + config.firebase + '.firebaseio.com/maps/' + mapId);
endpoint.on('child_added', function(childSnapshot) {
var uuid = childSnapshot.key()
var point = childSnapshot.val()
if (uuid === myUuid) return
addPoint(uuid, point)
})
endpoint.on('child_changed', function(childSnapshot) {
var uuid = childSnapshot.key()
var point = childSnapshot.val()
if (uuid === myUuid) return
putPoint(uuid, point)
})
endpoint.on('child_removed', function(oldChildSnapshot) {
var uuid = oldChildSnapshot.key()
removePoint(uuid)
})
//
// Tracking
//
var watchPositionId;
var currentCoords = null;
var currentOrientation = null;
function pushCurrentStatus() {
if (!currentCoords) return
endpoint.child(myUuid).set({
coords: {
latitude: currentCoords.latitude,
longitude: currentCoords.longitude,
},
orientation: currentOrientation,
timestamp: now()
})
}
pushCurrentStatus = _.throttle(pushCurrentStatus, 50)
if (navigator.geolocation) {
setTimeout(function() {
watchPositionId = navigator.geolocation.watchPosition(
successWatchPosition,
failWatchPosition,
{enableHighAccuracy: false}
)
}, 0)
setTimeout(function() {
navigator.geolocation.clearWatch(watchPositionId)
watchPositionId = navigator.geolocation.watchPosition(
successWatchPosition,
failWatchPosition,
{enableHighAccuracy: true}
)
}, 5000)
}
function successWatchPosition(position) {
if (!position.coords) return
currentCoords = position.coords
pushCurrentStatus()
putPoint(myUuid, {coords: currentCoords, orientation: currentOrientation})
}
function failWatchPosition() {
alert('Fail to get your location')
}
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', deviceOrientationHandler, true)
}
function deviceOrientationHandler(event) {
var alpha;
if (event.webkitCompassHeading) {
alpha = event.webkitCompassHeading;
} else {
alpha = event.alpha;
}
if (!alpha) return
currentOrientation = 360 - alpha
pushCurrentStatus()
putPoint(myUuid, {coords: currentCoords, orientation: currentOrientation})
}
//
// Remove old markers
//
setInterval(function() {
endpoint.limitToFirst(100).once('value', function(snap) {
var now = Math.floor(Date.now() / 1000)
snap.forEach(function(childSnapshot) {
var uuid = childSnapshot.key()
var point = childSnapshot.val()
if (uuid === myUuid) return
if (childSnapshot.val().timestamp < now - 60 * 30) {
endpoint.child(uuid).set(null)
} else {
updatePoint(uuid, point)
}
})
})
}, 5000);
})();

Related

Not able to use the updated value -- Flutter

I'm updating the totalPayable value in else if, but I'm not able to use the updated value anywhere in the code when I call getOrder(). Is it an API problem or what can anyone help me with the code?
else if (isOrderInitiated == false){
getCleintOrderFromApi();
debugPrint("ifelse" + totalPayable.toString());
}
getClientOrderFromApi() {
orders.clear();
totalPayable = 0.0;
api.getCleintOrder().then((list) {
list.forEach((order) {
if(order.is_placed) {
order.status = ORDER_STATUS[0];
} else if(!order.is_placed) {
order.status = ORDER_STATUS[2];
}
debugPrint("ORDER_STATUS from remote" + order.status);
for (var j = 0; j < order.items.length; j++) {
FoodItemOrder item = order.items[j];
totalPayable = totalPayable + item.unitPrice * item.quantity;
debugPrint(" total payable in order "+ totalPayable.toString());
}
orders.add(order);
debugPrint("itemsin order"+orders.last.items.length.toString());
});
currentOrderList.clear();
currentOrderList.addAll(orders);
orderItemsSink.add(orders);
});
}
}
The debugPrint in getClientOrderFromApi() is showing the updated result, but in else if debugPrint(" ifelse "+ totalPayable.toString()); it is not showing the updated value which is why wherever I use totalPayable it is not showing the desired value.
Future<List<Order>> getCleintOrder() async {
MakeOrder clientOrderRequest = MakeOrder(); //currentCafe;
clientOrderRequest.caffeID = currentCafe.caffeId;
clientOrderRequest.tableidtimestamp = currentUser.tableIdTimestamp;
// offset = 160;
String url = BASE_URL + BASE_URL_GET_CLIENT_ORDER;
debugPrint("requesting getCleintOrder --- \n" +
url +
"\n " +
clientOrderRequest.toClietnOrderJson().toString());
var response = await http
.post(
url,
headers: {
HttpHeaders.contentTypeHeader: 'application/json',
// HttpHeaders.authorizationHeader : ''
},
body: json.encode(clientOrderRequest.toClietnOrderJson()),
)
.catchError(
(error) {
////debugPrint(error.toString());
return false;
},
);
var jsonObj = json.decode(response.body);
////debugPrint(jsonObj.toString());
List<Order> orders = [];
try {
jsonObj.forEach((newJson) {
List<Order> orderList = (newJson["orders"] as List)
.map((neworderJson) => Order.fromJSON(neworderJson))
.toList().cast<Order>();
orders.addAll(orderList);
});
} catch (e) {
////debugPrint(e.toString());
}
// debugPrint("total client orders " + orders.length.toString());
return orders;
}
This is my api call for refernece.

Rails Nested complex Form

I'am looking a good ideas to build a cacsade forms.
what Iam looking for is to build a form to construct a config yml data.
for example to build key value form and the value field can be string or hash or array.
config --> Items --> has key and value --> can be String, Array or Hash.
Any Idea please?
what i did is to generate a graphe using 3djs and make editabe a node and handle add/ remove a node. I share whith you what I did for persons want do the same thing... (flare.json is the action to retrive json file )
var root;
treeJSON = d3.json("flare.json", function(error, treeData) {
// Calculate total nodes, max label length
var totalNodes = 0;
var maxLabelLength = 0;
// variables for drag/drop
var selectedNode = null;
var draggingNode = null;
// panning variables
var panSpeed = 200;
var panBoundary = 20; // Within 20px from edges will pan when dragging.
// Misc. variables
var i = 0;
var duration = 750;
// var root;
// size of the diagram
var viewerWidth = $('#d3view').width();
var viewerHeight = 800;
var tree = d3.layout.tree()
.size([viewerHeight, viewerWidth]);
// define a d3 diagonal projection for use by the node paths later on.
var diagonal = d3.svg.diagonal()
.projection(function(d) {
return [d.y, d.x];
});
// A recursive helper function for performing some setup by walking through all nodes
function visit(parent, visitFn, childrenFn) {
if (!parent) return;
visitFn(parent);
var children = childrenFn(parent);
if (children) {
var count = children.length;
for (var i = 0; i < count; i++) {
visit(children[i], visitFn, childrenFn);
}
}
}
// Call visit function to establish maxLabelLength
visit(treeData, function(d) {
totalNodes++;
maxLabelLength = Math.max(d.name.length, maxLabelLength);
}, function(d) {
return d.children && d.children.length > 0 ? d.children : null;
});
// sort the tree according to the node names
function sortTree() {
tree.sort(function(a, b) {
return b.name.toLowerCase() < a.name.toLowerCase() ? 1 : -1;
});
}
// Sort the tree initially incase the JSON isn't in a sorted order.
sortTree();
// Define the zoom function for the zoomable tree
function zoom() {
$('.btn-form').remove()
svgGroup.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}
// define the zoomListener which calls the zoom function on the "zoom" event constrained within the scaleExtents
var zoomListener = d3.behavior.zoom().scaleExtent([0.1, 1.5]).on("zoom", zoom);
// define the baseSvg, attaching a class for styling and the zoomListener
var baseSvg = d3.select("#d3view").append("svg")
.attr("width", viewerWidth)
.attr("height", viewerHeight)
.attr("class", "overlay")
.call(zoomListener);
// Function to center node when clicked/dropped so node doesn't get lost when collapsing/moving with large amount of children.
function centerNode(source) {
scale = 0.3;//zoomListener.scale();
x = -source.y0;
y = -source.x0;
x = x * scale + viewerWidth / 20;
y = y * scale + viewerHeight / 2.5;
d3.select('g').transition()
.duration(duration)
.attr("transform", "translate(" + x + "," + y + ")scale(" + scale + ")");
zoomListener.scale(scale);
zoomListener.translate([x, y]);
}
// Toggle children function
function toggleChildren(d) {
if (d.children) {
d._children = d.children;
d.children = null;
} else if (d._children) {
d.children = d._children;
d._children = null;
}
return d;
}
// Toggle children on click.
function click(d) {
if (d3.event.defaultPrevented) return; // click suppressed
d = toggleChildren(d);
update(d);
// centerNode(d);
}
function remove_link(d){
a = d3.event
a.preventDefault()
p = d.parent
parent_array = [p]
depth = d.depth - 1
for(var i=1; i<depth; i++){
parent_1 = p
parent_2 = parent_1.parent
parent_array.push(parent_2)
p = parent_2
}
parent_array[0].children.splice($.inArray(d, parent_array[0].children), 1)
update(d);
$('#editme').tree('loadData', [root]);
}
function make_editable(d)
{
// console.log("make_editable", arguments);
this
.on("mouseover", function() {
$('.btn-form').remove();
$('.input-form').remove();
d3.selectAll('text').style('fill', null)
d3.select(this).style("fill", "red");
var p = this.parentNode;
var xy = this.getBBox();
var p_xy = p.getBBox();
xy.x -= p_xy.x;
xy.y -= p_xy.y;
xy.x += 25;
xy.y -= 50;
var el = d3.select(this);
var p_el = d3.select(p);
var frm = p_el.append("foreignObject");
var inp = frm
.attr('class', 'btn-form')
.attr("x", xy.x)
.attr("y", xy.y)
.attr("width", 145)
.attr("height", 60)
.append("xhtml:form")
.append('a').text('Add').attr('class', 'btn btn-primary').attr('style', 'width:50px;height:30px;margin-right:2%;').on('click', add_link)
frm.select('form').append('a').text('Remove').attr('class', 'btn btn-danger remove-btn').attr('style', 'width:70px;height:30px;').on('click', remove_link)
frm.on('mouseover', function(){
$('.btn-form').closest('g').find('text').attr("fill", 'red');
})
.on('mouseout', function(){
$('.btn-form').closest('g').find('text').attr("fill", null);
})
})
.on("mouseout", function() {
d3.select(this).style("fill", null);
})
.on("click", function(d, event) {
e = d3.event;
e.preventDefault();
$('.btn-form').remove();
var p = this.parentNode;
// console.log(this, arguments);
// inject a HTML form to edit the content here...
// bug in the getBBox logic here, but don't know what I've done wrong here;
// anyhow, the coordinates are completely off & wrong. :-((
var xy = this.getBBox();
var p_xy = p.getBBox();
xy.x -= p_xy.x;
xy.y -= p_xy.y;
var el = d3.select(this);
var p_el = d3.select(p);
var frm = p_el.append("foreignObject");
var inp = frm
.attr('class', 'input-form')
.attr("x", xy.x)
.attr("y", xy.y)
.style("z-index", 99999)
.attr("width", 300)
.attr("height", 25)
.append("xhtml:form")
.append("input")
.attr("value", function() {
// nasty spot to place this call, but here we are sure that the <input> tag is available
// and is handily pointed at by 'this':
this.focus();
return el.text();
})
.attr("style", "width: 110px;")
// make the form go away when you jump out (form looses focus) or hit ENTER:
.on("blur", function() {
// console.log("blur", this, arguments);
var txt = inp.node().value;
el.text(function(d) { return txt; });
d.name = el.text();
// Note to self: frm.remove() will remove the entire <g> group! Remember the D3 selection logic!
p_el.select("foreignObject").remove();
})
.on("keypress", function() {
// console.log("keypress", this, arguments);
// IE fix
if (!d3.event)
d3.event = window.event;
var e = d3.event;
if (e.keyCode == 13)
{
if (typeof(e.cancelBubble) !== 'undefined') // IE
e.cancelBubble = true;
if (e.stopPropagation)
e.stopPropagation();
e.preventDefault();
var txt = inp.node().value;
el.text(function(d) { return txt; });
p_el.attr('data-name', txt);
d.name = el.text();
$('#editme').tree('loadData', [root]);
}
});
});
}
function add_link(d){
d3.event.preventDefault();
var p = $(this).closest('form')
var xy = $(this).closest('.btn-form')[0].getBBox();
if($(".add-link").length == 0){
var frm = p.append("<div><input type='text' class='add-link' style='width:130px;'></input></div>");
var inp = frm.on('keypress', function(event){
var e = event;
if (e.keyCode == 13)
{
e.preventDefault();
var txt = $('.add-link').val();
var event = document.createEvent('Event');
event.initEvent('click', true, true);
if(d.children){
d.children.push({name: txt})
}else if(d._children){
d._children.push({name: txt})
}else{
d.children = [{name: txt}]
}
$('text[fill="red"]').attr('fill', null);
update(root);
$(".btn-form").hide();
$('#editme').tree('loadData', [root]);
}
})
.on('click', function(event){ event.preventDefault();})
$('.add-link').focus()
}
}
function update(source) {
// Compute the new height, function counts total children of root node and sets tree height accordingly.
// This prevents the layout looking squashed when new nodes are made visible or looking sparse when nodes are removed
// This makes the layout more consistent.
var levelWidth = [1];
var childCount = function(level, n) {
if (n.children && n.children.length > 0) {
if (levelWidth.length <= level + 1) levelWidth.push(0);
levelWidth[level + 1] += n.children.length;
n.children.forEach(function(d) {
childCount(level + 1, d);
});
}
};
childCount(0, root);
var newHeight = d3.max(levelWidth) * 25; // 25 pixels per line
tree = tree.size([newHeight, viewerWidth]);
// Compute the new tree layout.
var nodes = tree.nodes(root).reverse(),
links = tree.links(nodes);
// Set widths between levels based on maxLabelLength.
nodes.forEach(function(d) {
d.y = (d.depth * (maxLabelLength * 10)); //maxLabelLength * 10px
// alternatively to keep a fixed scale one can set a fixed depth per level
// Normalize for fixed-depth by commenting out below line
// d.y = (d.depth * 500); //500px per level.
});
// Update the nodes…
node = svgGroup.selectAll("g.node")
.data(nodes, function(d) {
return d.id || (d.id = ++i);
});
// Enter any new nodes at the parent's previous position.
var nodeEnter = node.enter().append("g")
// .call(dragListener)
.attr("class", "node")
.attr("transform", function(d) {
return "translate(" + source.y0 + "," + source.x0 + ")";
})
.on('click', click);
nodeEnter.append("circle")
.attr('class', 'nodeCircle')
.attr("r", 0)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
nodeEnter.append("text")
.attr("x", function(d) {
return d.children || d._children ? -10 : 10;
})
.attr("dy", ".35em")
.attr('class', 'nodeText')
.attr("text-anchor", function(d) {
return d.children || d._children ? "end" : "start";
})
.text(function(d) {
return d.name;
})
.style("fill-opacity", 0)
.call(make_editable);
// phantom node to give us mouseover in a radius around it
// nodeEnter.append("circle")
// .attr('class', 'ghostCircle')
// .attr("r", 30)
// .attr("opacity", 0.2) // change this to zero to hide the target area
// .style("fill", "red")
// .attr('pointer-events', 'mouseover');
// .on("mouseover", function(node) {
// overCircle(node);
// })
// .on("mouseout", function(node) {
// outCircle(node);
// });
// Update the text to reflect whether node has children or not.
node.select('text')
.attr("x", function(d) {
return d.children || d._children ? -10 : 10;
})
.attr("text-anchor", function(d) {
return d.children || d._children ? "end" : "start";
})
.text(function(d) {
return d.name;
});
// Change the circle fill depending on whether it has children and is collapsed
node.select("circle.nodeCircle")
.attr("r", 4.5)
.style("fill", function(d) {
return d._children ? "lightsteelblue" : "#fff";
});
// Transition nodes to their new position.
var nodeUpdate = node.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
});
// Fade the text in
nodeUpdate.select("text")
.style("fill-opacity", 1);
// Transition exiting nodes to the parent's new position.
var nodeExit = node.exit().transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + source.y + "," + source.x + ")";
})
.remove();
nodeExit.select("circle")
.attr("r", 0);
nodeExit.select("text")
.style("fill-opacity", 0);
// Update the links…
var link = svgGroup.selectAll("path.link")
.data(links, function(d) {
return d.target.id;
});
// Enter any new links at the parent's previous position.
link.enter().insert("path", "g")
.attr("class", "link")
.attr("d", function(d) {
var o = {
x: source.x0,
y: source.y0
};
return diagonal({
source: o,
target: o
});
});
// Transition links to their new position.
link.transition()
.duration(duration)
.attr("d", diagonal);
// Transition exiting nodes to the parent's new position.
link.exit().transition()
.duration(duration)
.attr("d", function(d) {
var o = {
x: source.x,
y: source.y
};
return diagonal({
source: o,
target: o
});
})
.remove();
// Stash the old positions for transition.
nodes.forEach(function(d) {
d.x0 = d.x;
d.y0 = d.y;
});
}
function collapse(d) {
if (d.children) {
d._children = d.children;
d._children.forEach(collapse);
d.children = null;
}
}
function expand(d) {
if (d._children) {
d.children = d._children;
d.children.forEach(expand);
d._children = null;
}else if(d.children) {
d.children.forEach(expand);
}
}
// Append a group which holds all nodes and which the zoom Listener can act upon.
var svgGroup = baseSvg.append("g");
// Define the root
root = treeData;
root.x0 = viewerHeight / 2;
root.y0 = 0;
// Layout the tree initially and center on the root node.
update(root);
centerNode(root);
});

Cant stream video (PFFile) from parse server

I am having trouble streaming video with my iOS app from URL of a PFFile uploaded in my database. I used Heroku and AWS and I still have the same issue. It used to work fine when the files were hosted in the old parse server.
the PFFile url works fine when I open it in a chrome web browser but not in safari nor in the iOS app.
the following is the link of the video:
http://shuuapp.herokuapp.com/parse/files/wnQeou0L4klDelSEtMOX6SxXRVKu1f3sKl6vg349/24092609eadcc049f711aafbd59c1a18_movie.mp4
Its exactly the same issue as the issue mentioned in the link below:
iOS - Can't stream video from Parse Backend
parse-server doesn't seem to be supporting streaming in Safari/iOS and the solution is the enable it using express & GridStore as follows,
parse-server-example\node_modules\parse-server\lib\Routers\FilesRouter
{
key: 'getHandler',
value: function getHandler(req, res, content) {
var config = new _Config2.default(req.params.appId);
var filesController = config.filesController;
var filename = req.params.filename;
var video = '.mp4'
var lastFourCharacters = video.substr(video.length - 4);
if (lastFourCharacters == '.mp4') {
filesController.handleVideoStream(req, res, filename).then(function (data) {
}).catch(function (err) {
console.log('404FilesRouter');
res.status(404);
res.set('Content-Type', 'text/plain');
res.end('File not found.');
});
}else{
filesController.getFileData(config, filename).then(function (data) {
res.status(200);
res.end(data);
}).catch(function (err) {
res.status(404);
res.set('Content-Type', 'text/plain');
res.end('File not found.');
});
}
}
} , ...
parse-server-example\node_modules\parse-server\lib\Controllers\FilesController
_createClass(FilesController, [{
key: 'getFileData',
value: function getFileData(config, filename) {
return this.adapter.getFileData(filename);
}
},{
key: 'handleVideoStream',
value: function handleVideoStream(req, res, filename) {
return this.adapter.handleVideoStream(req, res, filename);
}
}, ...
parse-server-example\node_modules\parse-server\lib\Adapters\Files\GridStoreAdapter
... , {
key: 'handleVideoStream',
value: function handleVideoStream(req, res, filename) {
return this._connect().then(function (database) {
return _mongodb.GridStore.exist(database, filename).then(function () {
var gridStore = new _mongodb.GridStore(database, filename, 'r');
gridStore.open(function(err, GridFile) {
if(!GridFile) {
res.send(404,'Not Found');
return;
}
console.log('filename');
StreamGridFile(GridFile, req, res);
});
});
})
}
}, ...
Bottom of GridStore Adapter
function StreamGridFile(GridFile, req, res) {
var buffer_size = 1024 * 1024;//1024Kb
if (req.get('Range') != null) { //was: if(req.headers['range'])
// Range request, partialle stream the file
console.log('Range Request');
var parts = req.get('Range').replace(/bytes=/, "").split("-");
var partialstart = parts[0];
var partialend = parts[1];
var start = partialstart ? parseInt(partialstart, 10) : 0;
var end = partialend ? parseInt(partialend, 10) : GridFile.length - 1;
var chunksize = (end - start) + 1;
if(chunksize == 1){
start = 0;
partialend = false;
}
if(!partialend){
if(((GridFile.length-1) - start) < (buffer_size) ){
end = GridFile.length - 1;
}else{
end = start + (buffer_size);
}
chunksize = (end - start) + 1;
}
if(start == 0 && end == 2){
chunksize = 1;
}
res.writeHead(206, {
'Cache-Control': 'no-cache',
'Content-Range': 'bytes ' + start + '-' + end + '/' + GridFile.length,
'Accept-Ranges': 'bytes',
'Content-Length': chunksize,
'Content-Type': 'video/mp4',
});
GridFile.seek(start, function () {
// get GridFile stream
var stream = GridFile.stream(true);
var ended = false;
var bufferIdx = 0;
var bufferAvail = 0;
var range = (end - start) + 1;
var totalbyteswanted = (end - start) + 1;
var totalbyteswritten = 0;
// write to response
stream.on('data', function (buff) {
bufferAvail += buff.length;
//Ok check if we have enough to cover our range
if(bufferAvail < range) {
//Not enough bytes to satisfy our full range
if(bufferAvail > 0)
{
//Write full buffer
res.write(buff);
totalbyteswritten += buff.length;
range -= buff.length;
bufferIdx += buff.length;
bufferAvail -= buff.length;
}
}
else{
//Enough bytes to satisfy our full range!
if(bufferAvail > 0) {
var buffer = buff.slice(0,range);
res.write(buffer);
totalbyteswritten += buffer.length;
bufferIdx += range;
bufferAvail -= range;
}
}
if(totalbyteswritten >= totalbyteswanted) {
// totalbytes = 0;
GridFile.close();
res.end();
this.destroy();
}
});
});
}else{
// res.end(GridFile);
// stream back whole file
res.header('Cache-Control', 'no-cache');
res.header('Connection', 'keep-alive');
res.header("Accept-Ranges", "bytes");
res.header('Content-Type', 'video/mp4');
res.header('Content-Length', GridFile.length);
var stream = GridFile.stream(true).pipe(res);
}
};
P.S
The original answer is given by #Bragegs here - https://github.com/ParsePlatform/parse-server/issues/1440#issuecomment-212815625 .

Pinch and zoom not working on ipad

I am unable to do pinch and zoom on ipad, I guess that the below given code may be effecting the code,
Please give any perfect solution.
Is there any issue with the binding of body child events or need to calculate the touches in different variables, and do manual calculation.
///I-Pad evenet Binding
$(document).ready(function () {
$("body").children().bind('touchstart touchmove touchend touchcancel', function () {
var touches = event.changedTouches, first = touches[0], type = "";
switch (event.type) {
case "touchstart": type = "mousedown";
break;
case "touchmove": type = "mousemove";
break;
case "touchend": type = "mouseup";
break;
default: return;
}
var simulatedEvent = document.createEvent("MouseEvent");
simulatedEvent.initMouseEvent(type, true, true, window, 1,
first.screenX, first.screenY,
first.clientX, first.clientY, false,
false, false, false, 0/*left*/, null);
if (touches.length < 2) {
first.target.dispatchEvent(simulatedEvent);
event.preventDefault();
}
});
(function () {
var last_x = null, last_y = null, w_area = workarea[0],
panning = false, keypan = false, dopanning = false;
$("#svgroot").bind('mousemove mouseup', function (evt) {
if (dopanning === false) return;
var clientxnew = +$("#svgcontent")[0].getAttribute("x"),
clientynew = +$("#svgcontent")[0].getAttribute("y");
clientxnew += (evt.clientX - last_x);
clientynew += (evt.clientY - last_y);
last_x = evt.clientX;
last_y = evt.clientY;
//this.setAttribute("viewBox", vb.join(' '));
// updateCanvas(true);
$("#svgcontent").show();
$("#svgcontent")[0].setAttribute("x", clientxnew);
$("#svgcontent")[0].setAttribute("y", clientynew);
svgedit.select.getSelectorManager().selectorParentGroup.setAttribute("transform", "translate(" + clientxnew + "," + clientynew + ")");
if (evt.type === 'mouseup') { dopanning = false; }
return false;
}).mousedown(function (evt) {
var mouse_target = svgCanvas.getMouseTarget(evt);
if (svgCanvas.getMode() == "text" || svgCanvas.getMode() == "textedit") {
dopanning = false; return;
}
if ((mouse_target.id.indexOf("grouplayerdragged") > -1 || mouse_target.id.indexOf("hotspot") > -1 ||
mouse_target.id.indexOf("clonediv") > -1 || mouse_target.tagName === "text")) { dopanning = false; return; }
if (selectedElement != null) {
dopanning = false; return;
}
if (evt.button === 0) {
dopanning = true;
last_x = evt.clientX;
last_y = evt.clientY;
svgCanvas.clearSelection(true);
return false;
}
});
$(window).mouseup(function () {
panning = false;
dopanning = false;
});
you should use gesturechange. try this way (this is not your exact solution but you can hack it)
var angle = 0;
var newAngle;
var scale = 1;
var newScale;
function saveChanges() {
angle = newAngle;
scale = newScale;
}
function getAngleAndScale(e) {
// Don't zoom or rotate the whole screen
e.preventDefault();
// Rotation and scale are event properties
newAngle = angle + e.rotation;
newScale = scale * e.scale;
// Combine scale and rotation into a single transform
var tString = "scale(" + newScale + ")";
document.getElementById("theDiv").style.webkitTransform = tString;
}
function init() {
// Set scale and rotation during gestures
document.getElementById("theDiv").addEventListener("gesturechange", getAngleAndScale, false);
// Preserve scale and rotation when gesture ends
document.getElementById("theDiv").addEventListener("gestureend", saveChanges, false);
}
<body>
<div style="width:300px;height:300px;overflow:scrool;-webkit-overflow-scrolling: touch;">
<img id="theDiv" style="width:100%;" src="http://animal.discovery.com/guides/wild-birds/gallery/mallard_duck.jpg" />
</div>
Try this on your ipad

How to setup Flot for iOS retina display

I have tested this on an iPad (3 generation). The line chart appears perfectly smooth.
http://justindarc.github.com/flot.touch/example/index.html
I have tried diffing the code with my flot code and cannot see any significant difference that would cause it to run in retina mode. My flot is version 0.7, same as his code. No matter what I try my own chart runs in non-retina mode.
What is the trick in running retina mode?
My setup code is rather long.
function setup_chart0(setup_options) {
var point_data = [];
if(setup_options.use_sample_data_for_chart0) {
point_data = generate_dummy_data(
setup_options.timestamp_generate_min,
setup_options.timestamp_generate_max
);
}
var average_data = henderson23(point_data);
var datasets = make_chart0_datasets(point_data, average_data);
if(is_dualaxis_detail_mode) {
datasets = make_chart0_dual_datasets(
[],
[],
[],
[]
);
}
var options = default_plot_options();
options.xaxis.min = setup_options.timestamp_visible_min;
options.xaxis.max = setup_options.timestamp_visible_max;
options.xaxis.panRange = [setup_options.timestamp_pan_min, setup_options.timestamp_pan_max];
options.yaxis.min = -0.025;
options.yaxis.max = 1.025;
options.yaxis.panRange = [-0.025, 1.025];
options.legend = { container: '#legend0', noColumns: 2 };
options.grid.markings = compute_markings_with_alertlevels;
if(is_dualaxis_detail_mode) {
options.y2axis = {};
options.y2axis.position = "right";
options.y2axis.min = -0.025;
options.y2axis.max = 1.025;
options.y2axis.panRange = [-0.025, 1.025];
options.legend = { container: '#legend_hidden', noColumns: 2 };
}
//save_as_file({ samples: point_data, average: average_data });
var el_placeholder0 = $("#placeholder0");
if(el_placeholder0.length){
//console.log('plotting chart 0');
var fade = false;
var el = el_placeholder0;
var el_outer = $("#placeholder0_outer");
var original_offset = el_outer.offset();
if(fade) {
el_outer.offset({ top: -5000, left: 0 }); // move plot container off screen
}
chart0 = $.plot(el, datasets, options);
if(fade) {
el.hide(); // hide plot - must do *after* creation
el_outer.offset(original_offset); // put plot back where it belongs
el.fadeIn('slow'); // fade in
}
/*var s = ' width: ' + chart0.width() + ' height: ' + chart0.height();
$('#label0').append(s);*/
if(solo_pan_mode) {
el.bind('plotpan', function (event, plot) {
set_data_should_redraw_chart0 = true;
set_data_should_redraw_chart1 = false;
set_data_should_redraw_chart2 = false;
fetch_data_for_chart(chart0, setup_options.timestamp);
show_loading_empty('#loader1');
show_loading_empty('#loader2');
});
el.bind('plotpanend', function (event, plot) {
set_data_should_redraw_chart0 = true;
set_data_should_redraw_chart1 = true;
set_data_should_redraw_chart2 = true;
copy_min_max(chart0, chart1, '#placeholder1');
copy_min_max(chart0, chart2, '#placeholder2');
hack_hide_loading_wheels = true;
maybe_hide_loading_wheels();
});
} else {
el.bind('plotpan', function (event, plot) {
fetch_data_for_chart(chart0, setup_options.timestamp);
sync_with_chart0();
});
}
}
}
I have modified jquery.flot.js like this:
In the top I have added
retinaMode = (window.devicePixelRatio > 1),
I have extended these functions
function makeCanvas(skipPositioning, cls) {
var c = document.createElement('canvas');
c.className = cls;
c.width = canvasWidth;
c.height = canvasHeight;
if (!skipPositioning)
$(c).css({ position: 'absolute', left: 0, top: 0 });
$(c).appendTo(placeholder);
if(retinaMode) {
c.width = canvasWidth * 2;
c.height = canvasHeight * 2;
c.style.width = '' + canvasWidth + 'px';
c.style.height = '' + canvasHeight + 'px';
}
if (!c.getContext) // excanvas hack
c = window.G_vmlCanvasManager.initElement(c);
// used for resetting in case we get replotted
c.getContext("2d").save();
if (retinaMode) {
c.getContext("2d").scale(2,2);
}
return c;
}
function getCanvasDimensions() {
canvasWidth = placeholder.width();
canvasHeight = placeholder.height();
if (canvasWidth <= 0 || canvasHeight <= 0)
throw "Invalid dimensions for plot, width = " + canvasWidth + ", height = " + canvasHeight;
}
function resizeCanvas(c) {
// resizing should reset the state (excanvas seems to be
// buggy though)
if (c.width != canvasWidth) {
c.width = canvasWidth;
if(retinaMode) {
c.width = canvasWidth * 2;
}
c.style.width = '' + canvasWidth + 'px';
}
if (c.height != canvasHeight) {
c.height = canvasHeight;
if(retinaMode) {
c.height = canvasHeight * 2;
}
c.style.height = '' + canvasHeight + 'px';
}
// so try to get back to the initial state (even if it's
// gone now, this should be safe according to the spec)
var cctx = c.getContext("2d");
cctx.restore();
// and save again
cctx.save();
if(retinaMode) {
cctx.scale(2, 2);
}
}

Resources