I want to show some simple chart in my web application, but using Flot on an Apple device with Retina display looks blurry.
I use the 'normal' viewport settings:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
and this container for Flot to draw in:
<div id="placeholder" style="width: 300px;height:400px;"></div>
This is what I get:
So obivously Flot doesn't use window.devicePixelRatio by default, so I wanted to help out with some custom code:
var newWidth = $(chart.getCanvas()).attr("width") * window.devicePixelRatio;
var newHeight = $(chart.getCanvas()).attr("height") * window.devicePixelRatio;
$(chart.getCanvas()).attr("width", newWidth);
$(chart.getCanvas()).attr("height", newHeight);
chart.setupGrid();
chart.draw();
This in fact changes the canvas' dimensions and they keep that way even after the drawing. On the iPhone 4S it tells me the canvas dimensions are now 600 * 800 (after the drawing), but it still doesn't look crisp.
Related
When I view a webpage in Safari on my iPhone XS Max, the following javascript statements output Portrait logical resolution / pixels: 414x896 / 1242x2688 as expected.
<script>
document.write("Portrait logical resolution / pixels: " +screen.width + "x" + screen.height + " / ");
document.write(screen.width * window.devicePixelRatio + "x" + screen.height * window.devicePixelRatio + "<br>");
</script>
I also have in CSS the following definitions:
#media screen and (min-width:800px) {
.minWidth:after{
content: '800px';
}
}
#media screen and (min-width:900px) {
.minWidth:after{
content: '900px';
}
}
#media screen and (min-width:1000px) {
.minWidth:after{
content: '1000px';
}
}
I am surprised to see on the page that the following line
<span class="minWidth">Min Width: </span> outputs:
Min Width: 900px
This means that the device's min-width >= 900px and < 1000px. This however doesn't agree with the device's Portrait logical resolution / pixels being 414x896 / 1242x2688
Any explanation to this?
Adding the viewport meta tag to my webpage solved the problem.
Apple documentation says about the viewport meta tag (https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html):
"Use the viewport meta tag to improve the presentation of your web content on iOS. Typically, you use the viewport meta tag to set the width and initial scale of the viewport. For example, if your webpage is narrower than 980 pixels, then you should set the width of the viewport to fit your web content. If you are designing an iPhone or iPod touch-specific web application, then set the width to the width of the device. Refer to Supported Meta Tags for a detailed description of the viewport meta tag."
I added the following line to my webpage's header:
<meta name="viewport" content="width=device-width, initial-scale=1">
And now Javascript's screen.width is consistent with #media min-width value.
On my iPhone XSmax I get:
Portrait logical resolution / pixels: 414x896 / 1242x2688
Min Width: 400
I'm loading this Collada (DAE) model with aframe 0.8.2 and using aframe-ar to display it over a Hiro marker:
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<script src="https://aframe.io/releases/0.8.2/aframe.min.js"></script>
<script src="https://cdn.rawgit.com/jeromeetienne/AR.js/1.5.5/aframe/build/aframe-ar.js"></script>
<body style='margin : 0px; overflow: hidden;'>
<a-scene embedded arjs='trackingMethod: best; debugUIEnabled: false;'>
<!--a-marker type='pattern' url='https://rawgit.com/germanviscuso/AR.js/master/data/data/patt.gafas'-->
<a-marker preset='hiro'>
<a-collada-model src="url(https://aframe.io/aframe/examples/showcase/shopping/man/man.dae)"></a-collada-model>
</a-marker>
<a-camera-static/>
</a-scene>
</body>
Codepen: https://codepen.io/germanviscuso/pen/KRMgwz
I would like to know how to add controls to rotate it on its Y axis (with respect to the marker) by using swipe gestures on a mobile phone browser and to scale the model dynamically when doing pinch gestures. Ideally it would be nice if it also works with the mouse/touchpad when I'm testing in my laptop but touch on the phone is enough.
Can universal-controls handle this? Any example that I can see? This has to work while the model is being rendered dynamically with respect to the marker (AR tracking).
Any help is appreciated, thanks!
I wouldn't use the "native" controls based off raycaststers. Instead I would use any js gesture detection library. In this example i used hammer.js.
hammer.js registers an object which emits events when pan, swipe, pinch gestures are detected. I've created the object with the listeners in an a-frame component.
When pan is detected i just rotate the model depending on the direction (2 - left, 4 - right, 8 - up, 16 - down)
When pinch is detected i change the scale, depending on the event value, you can multiply by any factor. The component is below:
AFRAME.registerComponent("foo",{
init:function() {
var element = document.querySelector('body');
this.marker = document.querySelector('a-marker')
var model = document.querySelector('a-collada-model');
var hammertime = new Hammer(element);
var pinch = new Hammer.Pinch(); // Pinch is not by default in the recognisers
hammertime.add(pinch); // add it to the Manager instance
hammertime.on('pan', (ev) => {
let rotation = model.getAttribute("rotation")
switch(ev.direction) {
case 2:
rotation.y = rotation.y + 4
break;
case 4:
rotation.y = rotation.y - 4
break;
case 8:
rotation.x = rotation.x + 4
break;
case 16:
rotation.x = rotation.x - 4
break;
default:
break;
}
model.setAttribute("rotation", rotation)
});
hammertime.on("pinch", (ev) => {
let scale = {x:ev.scale, y:ev.scale, z:ev.scale}
model.setAttribute("scale", scale);
});
}
});
Working glitch here. In my example i also check if the marker is visible, thought it could be convinient.
Working example here
Please take a look at the code below. It's drawing a circle onto the map. If the user clicks with the mouse or taps with his finger (on a mobile device) into the circle and drags it, the circle should be moved across the map.
This works for Desktop Firefox, Desktop Chrome, Mobile Firefox. But not with Mobile Chrome. I think that the code in Mobile Firefox maybe just works because the browser emulates touch-inputs to mouse-inputs which of course are working well in Leaflet.
So I need help how to best implement touch events (parallel to mouse events) within Leaflet. Touch events are not mentioned in Leaflet's Doc. But i think the usual Javascript DOM-events should work too? (touchstart, touchmove, touchend). But not within Chrome mobile the way my code is written.
<!DOCTYPE html>
<html>
<head>
<title>Eventtest</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.1.0/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet#1.1.0/dist/leaflet.js"></script>
</head>
<body>
<div id="mapid" style="width: 600px; height: 400px;"></div>
<script>
var mymap = L.map('mapid').setView([51.505, -0.09], 13);
L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
maxZoom: 18,
attribution: 'Map data © OpenStreetMap contributors, ' +
'CC-BY-SA, ' +
'Imagery © Mapbox',
id: 'mapbox.streets'
}).addTo(mymap);
circle = L.circle([51.508, -0.11], 500, {
color: 'red',
fillColor: '#f03',
fillOpacity: 0.5
}).addTo(mymap);
circle.on('mousedown touchstart', onCircleDown);
function onCircleDown (e1) {
mymap.dragging.disable();
var mouseStartingLat = e1.latlng.lat;
var mouseStartingLng = e1.latlng.lng;
var circleStartingLat = e1.target._latlng.lat;
var circleStartingLng = e1.target._latlng.lng;
circle.on('mousemove', function (e2) {
var mouseNewLat = e2.latlng.lat;
var mouseNewLng = e2.latlng.lng;
var latDifference = mouseNewLat - mouseStartingLat;
var lngDifference = mouseNewLng - mouseStartingLng;
var currentCircleCoords = L.latLng (circleStartingLat + latDifference, circleStartingLng + lngDifference);
e1.target.setLatLng (currentCircleCoords);
});
circle.on ('mouseup', function () {
circle.off('mousemove');
mymap.dragging.enable();
});
}
</script>
</body>
</html>
if you look at this fiddle( http://jsfiddle.net/5ajYD/ ) with an android browser you see that the PNG that makes up the flowers has a white background.
On all other browsers it shows perfectly normal, except the android browser.
I've googled on this problem but the only thing I can find is a problem with png banding and related to android app programming.
This reminds me of the issues MSIE 6 has with transparant images, and I find it very strange that this happens.
Does anyone know a fix for this issue on android browsers?
I can't use non transparant background because of the gradient differences in different browsers.
What I have tried so far:
I have already tried using "multiple" backgrounds both posistioned at
location 0px 0px, but that doens't work
I've tried adding a gradient to to the div with the flowers, but that
failed too and broke in other browsers.
I find it very mystifying that this kind of issue shows up on a modern browser... even a nokia n95 gets it right....
The android version I’m testing against/found this with is android 2.3.4(Sony Ericsson Xperia Arc S LT18i)
This is what I see with the fiddle in the android browser on the phone
http://t.co/mofPkqjf
I had a big facepalm moment.
I've been battling with this for two months now and I simply couldn't figure out the logic. The problem was in the econtainer element that it had a parameter: width:100%.
What happens is that it only renders the width up to the actual page width of the viewport.
So if you have a browser screen on mobile that's 480px wide, it'll set width to 480px, render a gradient of 480px, and not rerender when you scroll sideways.
The problem was solved by adding a min-width:1200px; and now it renders properly!
Thank you all for looking into this...
Use HTML5 Canvas to create an alphaJPEG, a JPEG layered under an equivalent PNG with an alpha channel.
<head>
<style>img[data-alpha-src]{visibility: hidden;}</style>
</head>
<body>
<img src="image.jpg" data-alpha-src="alpha.png" />
<!--...-->
<script src="ajpeg.js"></script>
</body>
ajpeg.js
(function() {
var create_alpha_jpeg = function(img) {
var alpha_path = img.getAttribute('data-alpha-src')
if(!alpha_path) return
// Hide the original un-alpha'd
img.style.visiblity = 'hidden'
// Preload the un-alpha'd image
var image = document.createElement('img')
image.src = img.src
image.onload = function () {
// Then preload alpha mask
var alpha = document.createElement('img')
alpha.src = alpha_path
alpha.onload = function () {
var canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
img.parentNode.replaceChild(canvas, img)
// For IE7/8
if(typeof FlashCanvas != 'undefined') FlashCanvas.initElement(canvas)
// Canvas compositing code
var context = canvas.getContext('2d')
context.clearRect(0, 0, image.width, image.height)
context.drawImage(image, 0, 0, image.width, image.height)
context.globalCompositeOperation = 'xor'
context.drawImage(alpha, 0, 0, image.width, image.height)
}
}
}
// Apply this technique to every image on the page once DOM is ready
// (I just placed it at the bottom of the page for brevity)
var imgs = document.getElementsByTagName('img')
for(var i = 0; i < imgs.length; i++)
create_alpha_jpeg(imgs[i])
})();
In the head element I linked to FlashCanvas:
<!--[if lte IE 8]><script src="flashcanvas.js"></script><![endif]-->
... and I threw in this to avoid a flicker of the un-alpha’d JPEG:
I developed the following webpage: www.projekt-meine-zukunft.at
It is shown quite well in Safari, the problem is that two-finger zooming doesn't work. Now I have no idea why I can't make the webpage smaller with two-finger gesture like it works with other webpages. I would like to show you code-snippets, but I don't know which would help you.
Could it be a css-problem maybe?
The page is developed with Drupal by the way.
You have the following JavaScript code, which is presenting users from scaling by setting minimum-scale = 1, maximum-scale = 1:
// In Safari, the true version is after "Safari" or after "Version"
else if ((verOffset=nAgt.indexOf("Safari"))!=-1) {
browserName = "Safari";
document.writeln('<meta name="viewport" id="view" content="user-scalable=yes, width=device-width minimum-scale = 1, maximum-scale = 1" />');
document.writeln('<link rel="stylesheet" media="all and (orientation:portrait)" href="/themes/pmz/css/portrait.css" />');
}