Longitude, Latitude to OSM pixel in 256x256 Tile - javascript

OpenStreetMap (OSM) have a Tile server. A tile is a 256x256 image of the world in a specific zoom.
I have longitude and latitude and I can find the correct tile by using this function.
function long2tile(lon,zoom) {return (Math.floor((lon+180)/360*Math.pow(2,zoom))); }
function lat2tile(lat,zoom) { return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom))); }
var zoom = 4;
var x= long2tile(13.393562,zoom);
var y = lat2tile(52.519582,zoom);
document.getElementById('a').src='https://tile.openstreetmap.org/'+zoom+'/'+ x+'/'+y+'.png';
<img src="" id="a" style="border:1px solid black"/>
My problem is that Id like to know what coordinate in the 256x256 pixel is the location i set.
How to get the x-y coordiaten inside this one tile?

The rounding makes the difference!
function lo2t(lon,zoom){
return (lon+180)/360*Math.pow(2,zoom);
}
function la2t(lat,zoom){
return (1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom);
}
function long2tile(lon,zoom) {return Math.floor(lo2t(lon,zoom)); }
function lat2tile(lat,zoom) {return Math.floor(la2t(lat,zoom)); }
function long2tfac(lon,zoom) {
return long2tile(lon,zoom)-lo2t(lon,zoom);
}
function lat2tfac(lat,zoom) {
return lat2tile(lat,zoom)-la2t(lat,zoom);
}
var zoom = 4;
var x= long2tile(13.393562,zoom);
var y = lat2tile(52.519582,zoom);
document.getElementById('a').src='https://tile.openstreetmap.org/'+zoom+'/'+ x+'/'+y+'.png';
var point = document.getElementById('point');
var pos=";"; pos+="left:"+long2tfac(13.393562,zoom)*-256;
pos+="px;top:"+lat2tfac(52.519582,zoom)*-256;
point.setAttribute('style',point.getAttribute('style')+pos+'px;');
<img src="" id="a" style="border:1px solid black"/>
<div id="point" style="display:block; position:absolute; width:30px; height:30px; border:1px solid black; border-radius:15px;"> </div>

You can use the OpenLayers library for that purpose, it can manage all sort of calculations and transformations for you:
const source = new ol.source.OSM();
const grid = source.getTileGrid();
const projectedCoordinate=ol.proj.fromLonLat([13.393562,52.519582], "EPSG:3857");
const tileCoord = grid.getTileCoordForCoordAndZ(projectedCoordinate, 4/*zoom-level*/);
const projectedExtent=grid.getTileCoordExtent(tileCoord);
const extent = ol.proj.transformExtent(projectedExtent, ol.proj.get('EPSG:3857'), ol.proj.get('EPSG:4326'));
const yWidth=extent[2]-extent[0];
const xWidth=extent[3]-extent[1];
const tileUrlFunction = source.getTileUrlFunction();
const url=tileUrlFunction(tileCoord, 1, ol.proj.get('EPSG:3857'))
function convertPixelToLonLat(xPixel,yPixel){
if(!(xPixel>=0 && xPixel<=256)){
throw new Error('invalid xPixel');
}
if(!(yPixel>=0 && yPixel<=256)){
throw new Error('invalid yPixel');
}
return {lon:extent[1]+xWidth/256*xPixel,lat:extent[2]-yWidth/256*yPixel}
}
document.querySelector('img').src=url;
console.log("top-left of tile:",convertPixelToLonLat(0,0))
console.log("bottom-right of tile:",convertPixelToLonLat(256,256))
console.log("middle of tile:",convertPixelToLonLat(128,128))
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://cdn.rawgit.com/openlayers/openlayers.github.io/master/en/v5.3.0/build/ol.js"></script>
<title>Test</title>
</head>
<body>
<img />
</body>
</html>

Related

Ascii Art Animation in Browser

I want to animate Ascii Art in the Browser.
The Ascii Art should be loaded via a text file. There are many libraries which convert but I have found none, which actually animates it.
By animation I mean a typewriter animation that speeds up over time and changes the 'zoom factor' so that the whole image is visible in the viewport at the end.
Hopefully anyone knows a libary for my problem.
I have a feeling SO doesn't like library recommendations, and actually I haven't found one, so here's some basic code to get you started.
It sets the typing speed to the old Teletype 10 chars per second and of course that can be changed, and an acceleration function can be added when you know what you want for that. Note: the txt file needs to be on the same domain to prevent CORS problems.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Typewriter print</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Courier, monospace;
font-size: 12px;
}
</style>
</head>
<body>
<div id="container">
<input id="file" type="text" value="" placeholder="Filename" />
<button onclick="loadFile()">Click to draw the file</button>
<div id="picture"></div>
</div>
<script>
let file = '';
let reader = new XMLHttpRequest();
function loadFile() {
file = document.getElementById('file').value;
reader.open('get', file, true);
reader.onreadystatechange = draw;
reader.send(null);
}
function draw() {
if (reader.readyState == 4) {
const picture = document.getElementById('picture');
picture.innerHTML = '';
let str = reader.responseText;
let chs = str.split('');
//set as the typing speed in characters
//per second 10 is the old teletype speed
let chsPerSec = 10;
let i = 0;
function reveal() {
if (i < chs.length) {
let nextch = chs[i];
if (nextch.charCodeAt(0) == 10) {
nextch = '<br>';
} else if (nextch.charCodeAt(0) == 32) {
nextch = '<span style="color:transparent;">.</span>';
}
picture.innerHTML = picture.innerHTML + nextch;
setTimeout(reveal, Math.floor(1000 / chsPerSec));
i++;
}
}
reveal();
}
}
</script>
</body>
</html>

Cannot delete buttons using js

I can't delete two <button> tags using javascript. When you enter the wrong pin, I want the buttons to delete themselves but somehow it's not working.
var radar = document.getElementsByTagName("button");
var pin = 3778;
var pin_request = prompt("Podaj pin")
if (pin_request == pin) {
document.write("Podany pin: " + pin_request);
alert("Podano właściwy pin.");
} else {
document.write("odmowa dostępu.");
radar.parentNode.removeChild(radar);
}
<html>
<head>
<meta charset="UTF-8">
<style>
html {
text-align: center;
padding: 7em;
display: block;
}
button {
margin: 1cm;
}
</style>
</head>
<body><br>
<button>dodaj pieniądze</button>
<button>zainwestuj w nieruchomości</button>
<script src="do visual studio code.js"></script>
</body>
</html>
Also sorry for half-English code.
You can use querySelectorAll to get elements and in loop remove them.
var radar = document.querySelectorAll("button");
var pin = 3778;
var pin_request = prompt("Podaj pin")
if (pin_request == pin)
{
document.write("Podany pin: "+pin_request);
alert("Podano właściwy pin.");
}
else {
document.write("odmowa dostępu.");
radar.forEach(el=>{
el.remove();
})
}
<html>
<head>
<meta charset="UTF-8">
<style>
html{text-align:center; padding:7em; display:block;}
button{
margin:1cm;
}
</style>
</head>
<body><br>
<button>dodaj pieniądze</button>
<button>zainwestuj w nieruchomości</button>
<script src="do visual studio code.js"></script>
</body>
getElementyByTagName() returns an array of elements, but removeChild() only takes one element as an argument. If you use a loop it should work:
var parent = radar[0].parentNode
for(var i = 0; i < radar.length; i++) {
parent.removeChild(radar[i])
}
<!DOCTYPE HTML5>
<html>
<head>
<meta charset="UTF-8">
<style>
html{text-align:center; padding:7em; display:block;}
button{
margin:1cm;
}
</style>
</head>
<body><br>
<button>dodaj pieniądze</button>
<button>zainwestuj w nieruchomości</button>
<script>
var radar = document.querySelectorAll("button");
var pin = 3778;
var pin_request = prompt("Podaj pin")
if (pin_request == pin)
{
document.write("Podany pin: "+pin_request);
alert("Podano właściwy pin.");
}
else {
document.write("odmowa dostępu.");
radar.forEach(ele =>{
ele.remove();
})
}
</script>
</body>
</html>
This should work
var radar = document.getElementsByTagName("button");
var pin = 3778;
var pin_request = prompt("Podaj pin")
if (pin_request == pin)
{
document.write("Podany pin: "+pin_request);
alert("Podano właściwy pin.");
}
else {
document.write("odmowa dostępu.");
var elem = document.getElementById('btn1');
elem.parentNode.removeChild(elem);
var elem2 = document.getElementById('btn2');
elem2.parentNode.removeChild(elem2);
}
<button id = 'btn1'>dodaj pieniądze</button>
<button id = 'btn2'>zainwestuj w nieruchomości</button>

Javascript Font scaling code from body to div / element

I found some code which will scale some text when the browser window is resized and it seems to work well.
Here is the code:
document.body.setScaledFont = function (f) {
var s = this.offsetWidth,
fs = s * f;
this.style.fontSize = fs + '%';
return this
};
document.body.setScaledFont(0.35);
window.onresize = function () {
document.body.setScaledFont(0.35);
}
My question is:
How can I modify this code so the text scales when a specified div is scaled instead?
Updated code from suggested answer by #Deano. This code scales only when the browser is resized.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">
#window {
border:1px dashed #ccc;
overflow: hidden;
resize: both;
text-align: center;
}
</style>
</head>
<body>
<div id="window">Scale the window</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('#window').mouseup( function() {
document.getElementById('window').setScaledFont = function (f) {
var s = this.offsetWidth,
fs = s * f;
this.style.fontSize = fs + '%';
return this
};
document.getElementById('window').setScaledFont(0.35);
window.onresize = function () {
document.getElementById('window').setScaledFont(0.35);
}
});
});
</script>
</body>
</html>
document.body targets the entire body, if you want to target a specific element, use Id or class.
document.getElementById('window').setScaledFont = function (f) {
var s = this.offsetWidth,
fs = s * f;
this.style.fontSize = fs + '%';
return this
};
document.getElementById('window').setScaledFont(0.35);
window.onresize = function () {
document.getElementById('window').setScaledFont(0.35);
}
div {
font-size:2em;
}
<div id="window">Scale the window</div>
JSfiddle
Update Since the question requirement has changed :-/
You will need to use a libary like mimetic.js DEMO

I want to change this random function to onclick function

I am actually creating circles on page randomly and I want to draw these onclick function. But Which code I have is random function which randomly distribute on page. So how can I change this code to onclick ?
<!DOCTYPE html>
<html lang='en'>
<head>
<html>
<input type="text" name="test" style="width: 130px; height: 30px "value="" id="text" placeholder="Enter length"/>
</html>
<meta charset='utf-8' />
<script type='text/javascript' src='OpenLayers.js'></script>
<script type='text/javascript'>
var map;
var vector_layer;
function init() {
//Create a map with an empty array of controls
map = new OpenLayers.Map('map_element');
//Create a base layer
var wms_layer = new OpenLayers.Layer.WMS(
'OpenLayers WMS',
'http://vmap0.tiles.osgeo.org/wms/vmap0',
{layers: 'basic'},
{}
);
map.addLayer(wms_layer);
//Add vector layer
vector_layer = new OpenLayers.Layer.Vector('Settlement Vector Layer');
map.addLayer(vector_layer);
var settlement_values = {
4: 'circle'
}
//Create some points
for(var i=0; i<20; i++){
vector_layer.addFeatures([new OpenLayers.Feature.Vector(
new OpenLayers.Geometry.Point(
(Math.floor(Math.random() * 360) - 180),
(Math.floor(Math.random() * 180) - 90)
),
{
'settlement_type': settlement_values[(Math.floor(Math.random() * 15))]
}
)]);
}
//Create a style map object
var vector_style_map = new OpenLayers.StyleMap({});
//ADD RULES
//We need to create a 'lookup table' that contains the desired values
// and corresponding symbolizer
var x=document.getElementById("text").value;
var symbolizers_lookup = {
'circle': {
'fillColor': '#336699','fillOpacity':.8, 'pointRadius':x, 'strokeColor': '#003366', 'strokeWidth':2
}
}
//Now, call addUniqueValueRules and pass in the symbolizer lookups
vector_style_map.addUniqueValueRules('default', 'settlement_type', symbolizers_lookup);
//Add the style map to the vector layer
vector_layer.styleMap = vector_style_map;
if(!map.getCenter()){
map.zoomToMaxExtent();
}
}
</script>
</head>
<body onload='init();'>
<div id='map_element' style='width: 600px; height: 600px;'></div>
</body>
</html>
Change onload to onclick in your body tag.
<body onclick='init();'> <!-- <======== HERE -->
<div id='map_element' style='width: 600px; height: 600px;'></div>
</body>
</html>

Odd array behaviour in JavaScript

I'm attempting to draw boxes onto a canvas using JavaScript; my code works, but I'm having trouble with my arrays. Say I have a multi-demensional array called map and it is declared like so:
var map = [
[0,1,1],
[0,0,1],
[0,1,1],
];
Where 1 is a box and 0 is blank space, but when I run my code the output looks like the following:
0,0,0
1,0,1
1,1,1
Is there any way to fix this so the output matches map? My code looks like this:
var canvas = null;
var ctx = null;
var x,y,count,inc,ax,ay;
var map = [
[0,0,0],
[1,0,1],
[1,1,1],
];
window.onload = function () {
canvas = document.getElementById("gameArea");
ctx = canvas.getContext("2d");
y=0;
x=0;
ax=0;
ay=0;
count=0;
inc=0;
for(;count<3;count++){
if(count>0){
inc = inc + 40;
console.log("inc:"+inc);
console.log();
}
ay=count;
console.log("ay:"+ay);
console.log();
y = y + inc;
console.log("y:"+y);
console.log();
for(;ax<3;x=x+40,ax++){
if(map[ax][ay]==1){
console.log(ax+","+ay)
console.log(map[ax][ay]);
console.log();
ctx.strokeRect(x,y,40,40);
console.log("block:"+x+","+y);
}
}
console.log();
x=0;
y=0;
ax=0;
}
};
And the HTML is as follows:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Single Stage</title>
<script src="js/game.js" type="text/javascript">
</script>
<style type="text/css">
#gameArea{
display:block;
margin:0 auto;
background-color:#FFFFFF;
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="gameArea" width='800' height='480'></canvas>
</body>
</html>
You've just mixed up your rows and columns
try switching map[ax][ay]==1 to map[ay][ax]==1

Categories

Resources