ReactLeaflet with open street map- unable to fit in marker point exactly inside the image overlay - image

I am trying to fit an imageoverlay inside a map container with few marker points to be aligned accordingly.
outer/div container size is fixed height: "264px" width: "1179px",imageoverlay here is an image of airport bay with list of latitudes and longitude points for each bay locations,
I have 4 point coordinates of entire bay area which is to be covered, Problem is if I try to fit the image inside the 4 points image looks distorted, all the markers appears close to each other, and also it is not aligned with image overlay. I tried to rotate the image even then it didnt work.(2nd image for ref)
If I fit the image overlay based on the width/height image fits well, but markers are all scattered ,
Help is much appreciated , kindly excuse if the above explanation quite long.(1st image for ref)
unaligned markers
proper_markers_OSM_but_not_correctly_as_in_image
import * as React from "react";
import {useMemo,render,useState,useEffect } from "react";
import { LatLng, LatLngBounds,CRS,Transformation } from "leaflet";
import { MapContainer, TileLayer, ImageOverlay ,Marker, Popup,useMap,Rectangle, ZoomControl} from "react-leaflet";
import {data} from "./data/mockdata"
import aiportviewmap from './data/aiportviewmap.png'
const Bound = () => {
const outerBounds = [
  [1.3395283985838653, 103.97021804850274],
  [1.3875520864854187, 103.99121729409903],
  [1.3316406520024404, 103.98991242756328],
  [1.3820307764687148, 104.00684534524635],
] 
  function SetBoundsRectangles() {
  const [bounds, setBounds] = useState(outerBounds)
let calcbound=[];
data.map((row) =>{
calcbound.push([row.northLat,row.eastLong])
})
const bayBound=calcbound
const map = useMap()  
useEffect(()=>{
map.setView( [map.getCenter().lat, map.getCenter().lng],15)
// // map.invalidateSize();
// // setBounds(outerBounds)
// map.fitBounds(outerBounds)
},[])
return (
   <>
<ImageOverlay
// url={"https://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg"}
style={{ transform:'rotate(180deg)' }}
url={aiportviewmap}
bounds={ outerBounds}
// eventHandlers={innerHandlers}
opacity={0.8}
zIndex={10}
scale={1}
style={{transform:"rotate(90deg)" }}
whenReady={(e) => e.target.fitBounds(bayBound)}
/>
     </>
  )
} 
return(
  <MapContainer
center ={[1.3595963692439295,103.98853169687455]}
zoom={0}
// style={{ transform:"rotate(90deg)" }}
scrollWheelZoom={false}
crs={CRS.Simple}>
  <TileLayer
      attribution='© OpenStreetMap contributors'
      url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
    <SetBoundsRectangles />
{data.map((row) => {
console.log("row",row);
return (
<Marker
key={row.bayLocationCode}
position={[row.northLat, row.eastLong]}>
<Popup>
{row.bayLocationCode}
</Popup>
</Marker>);
})
}
  </MapContainer>
)
}
export default Bound;

Related

How to turn window background black on showing modal view in nativescript

As shown in the image 1 below, when the modal view on ios 13 shows up, the default background is black. But on nativescript, the default background is white as shown in the image 2. How to achieve the image 1 kind of background (black) using nativescript core? I tried changing the color of status bar but that actually changes the color of the top page portion that's partially visible in the images. I tried to define background-color on Frame css, but didn't work. Any suggestions? Thanks in advance.
Image 1:
Image 2:
The modal view options:
const option: ShowModalOptions = {
context: { selectedAccount: account },
closeCallback: (a, b, c, action) => {
//some code
},
fullscreen: false
};
mainView.showModal("./modal-add-page", option);
You have to set the background color of window on iOS.
Update: Nativescript 7
import * as app form "#nativescript/core/application";
import { Color } from "#nativescript/core/color";
import { isIOS } from '#nativescript/core';
if (isIOS) {
if (app.hasLaunched) {
app.ios.window.backgroundColor = new Color("black").ios;
} else {
app.on("launch", _ => app.ios.window.backgroundColor = new Color("black").ios)
}
}
Older versions:
import * as app form "tns-core-modules/application";
import { Color } from "tns-core-modules/color";
// You must run it once application is initiated
app.ios.window.backgroundColor = new Color("black").ios;

Nativescript-Vue Issue with Panning Elements around

So I am building a photo group creator in Nativescript-vue. I have the pan working and the view is rendering correctly. But my issue is when a user starts to pan the image outside the container it's in, the image goes 'behind' the container. And I need it to render ontop of everything. I have tried 'z-index' with css and still no go.
The idea is, there is a group of photos (un-grouped group). And the user will be able to click-and-drag a photo in the group down to an 'empty' group. And this in turn would create a new group. Or if there were other groups the user would be able to drag an image and add it to an existing group.
Any help or suggestions, thank you in advance!
This is my Vue Component
<template>
<StackLayout orientation="vertical" ref="mainContainer">
</StackLayout>
</template>
<script>
import * as StackLayout from 'tns-core-modules/ui/layouts/stack-layout';
import * as Image from 'tns-core-modules/ui/image';
import _ from 'underscore';
export default {
name: "photo-groupings",
props:{
photoList:{
type: Object,
required: true
}
},
mounted(){
let ungrouped = this.createGroupElement();
let newGroupElement = this.createGroupElement();
console.log(_.keys(this.photoList));
for(let pht of _.keys(this.photoList)){
console.log(pht);
console.log(this.photoList[pht]);
ungrouped.addChild(this.createImageChild(this.photoList[pht]))
}
this.$refs.mainContainer.nativeView.addChild(ungrouped);
this.$refs.mainContainer.nativeView.addChild(newGroupElement)
},
data(){
return {
photoGroups:{},
groupElements:{},
prevDeltaX: 0,
prevDeltaY: 0
}
},
methods:{
createImageChild(src){
let tempImg = new Image.Image();
tempImg.src = src;
tempImg.width = 100;
tempImg.height = 100;
tempImg.stretch = "aspectFill";
tempImg.borderRadius = 10;
tempImg.borderWidth = 2;
tempImg.borderColor = "forestgreen";
tempImg.margin = 5;
tempImg.on('pan', this.handlePan);
return tempImg;
},
createGroupElement(){
let tempGroup = new StackLayout.StackLayout();
tempGroup.orientation = "horizontal";
tempGroup.margin = 5;
tempGroup.borderColor = "black";
tempGroup.borderRadius = 5;
tempGroup.borderWidth = 1;
tempGroup.minHeight = 110;
return tempGroup;
},
handlePan(args){
if (args.state === 1) // down
{
this.prevDeltaX = 0;
this.prevDeltaY = 0;
console.log(args.view.getLocationRelativeTo(args.view.parent));
console.log(args.view.parent.getLocationInWindow());
}
else if (args.state === 2) // panning
{
args.view.translateX += args.deltaX - this.prevDeltaX;
args.view.translateY += args.deltaY - this.prevDeltaY;
this.prevDeltaX = args.deltaX;
this.prevDeltaY = args.deltaY;
}
else if (args.state === 3) // up
{
console.log("Pan release")
}
}
}
}
</script>
<style scoped>
</style>
Example Image of the images rendering 'behind'
The best way here would be creating a ghost element.
You should not move the original image but hide the original image when you detect drag, create a ghost of original image and insert it on the parent layout. When user drops the ghost image, destroy the ghost and move original image to destination.

How I can get Image coordinate in Nativescript with Angular2

I have an Image to show in my nativescript(with Angular2) app, where I want to make different part of image clickable. For example a human body image and I just want to know which part is clicked by the user.
Is there any way to create image-map just like html???
<CardView height="450" width="350" marginTop="10">
<Image src="res://nerves" height="304" width="114" horizontalAlignment="center" verticalAlignment="center"></Image>
</CardView>
Use the (touch) event binding on your Image element.
Here's an example that prints a console message when you click in the fourth quadrant of the image.
import {
Component
} from '#angular/core';
import * as platform from 'platform';
import {
TouchGestureEventData
} from 'tns-core-modules/ui/gestures';
#Component({
moduleId: module.id,
selector: 'your-component',
template: `
<GridLayout>
<Image src="res://your_image" width="128" height="128"
(touch)="touchImage($event)"
verticalAlignment="middle" horizontalAlignment="center"></Image>
</GridLayout>
`
})
export class YourComponent {
touchImage(event: TouchGestureEventData) {
// This is the density of your screen, so we can divide the measured width/height by it.
const scale: number = platform.screen.mainScreen.scale;
if (event.action === 'down') {
// this is the point that the user just clicked on, expressed as x/y
// values between 0 and 1.
const point = {
y: event.getY() / (event.view.getMeasuredHeight() / scale),
x: event.getX() / (event.view.getMeasuredWidth() / scale)
};
// add custom code to figure out if something significant was "hit"
if (point.x > 0.5 && point.y > 0.5) {
console.log('you clicked on the lower right part of the image.');
}
}
}
}

How to create events using React Native

I'm making an application using React VR. If you don't know React VR, well it's based on React Native with some other components, includes Three.js and other stuff, specific for using WebVR.
I've making a component named NavigateButton. Below is my code:
import React from 'react';
import { AppRegistry, asset, StyleSheet, Pano, Text, View, VrButton, Sphere } from 'react-vr';
export class NavigateButton extends React.Component {
render() {
return (
<VrButton onClick={() => this.onNavigating()}>
<Sphere radius={0.5} widthSegments={10} heightSegments={10} style={{ color: "red" }} />
</VrButton>
);
}
onNavigating() { // This method must throw an event
console.log(this.props.to);
}
};
If the user clicks on the VrButton (this is like a HTML 5 button-tag but for VR with inside it, a sphere), an event must been raised to the place where I call the NavigateButton component. That's on code below:
import React from 'react';
import { AppRegistry, asset, StyleSheet, Pano, Text, View, VrButton, Sphere } from 'react-vr';
import { NavigateButton } from './components/nativateButton.js';
let room = asset('360 LR/inkom_hal.jpg');
export default class MainComp extends React.Component {
render() {
return (
<View>
<Pano source={asset('360 LR/inkom_hal.jpg')} />
<View style={{ transform: [{ translate: [20, 0, 0] }] }}>
<NavigateButton to="garage"></NavigateButton>
<!-- and must been catch here -->
</View>
<View style={{ transform: [{ translate: [-7, 0, -20] }] }}>
<NavigateButton to="woonkamer"></NavigateButton>
<!-- or here -->
</View>
</View>
);
}
}
AppRegistry.registerComponent('MainComp', () => MainComp);
Is it possible to do that? I would something like code below to catch the event:
<NavigateButton to="woonkamer" onNavigate={() => this.change()}></NavigateButton>
I've searched on the internet but nothing found that could help me.
Here is the instruction how to create Sample VR app with React VR prepared by me and my team:
Creating a VR tour for web
The structure of future app’s directory is as follows:
+-node_modules
+-static_assets
+-vr
\-.gitignore
\-.watchmanconfig
\-index.vr.js
\-package.json
\-postinstall.js
\-rn-cli-config.js
The code of a web app would be in the index.vr.js file, while the static_assets directory hosts external resources (images, 3D models). You can learn more on how to get started with React VR project here. The index.vr.js file contains the following:
import React from 'react';
import {
AppRegistry,
asset,
StyleSheet,
Pano,
Text,
View,
}
from 'react-vr';
class TMExample extends React.Component {
render() {
return (
<View>
<Pano source={asset('chess-world.jpg')}/>
<Text
style={{
backgroundColor:'blue',
padding: 0.02,
textAlign:'center',
textAlignVertical:'center',
fontSize: 0.8,
layoutOrigin: [0.5, 0.5],
transform: [{translate: [0, 0, -3]}],
}}>
hello
</Text>
</View>
);
}
};
AppRegistry.registerComponent('TMExample', () => TMExample);
VR components in use
We use React Native packager for code pre-processing, compilation, bundling and asset loading. In render function there are view, pano and text components. Each of these React VR components comes with a style attribute to help control the layout.
To wrap it up, check that the root component gets registered with AppRegistry.registerComponent, which bundles the application and readies it to run. Next step to highlight in our React VR project is compiling 2 main files.
Index.vr.js file
In constructor we’ve indicated the data for VR tour app. These are scene images, buttons to switch between scenes with X-Y-Z coordinates, values for animations. All the images we contain in static_assets folder.
constructor (props) {
super(props);
this.state = {
scenes: [{scene_image: 'initial.jpg', step: 1, navigations: [{step:2, translate: [0.73,-0.15,0.66], rotation: [0,36,0] }] },
{scene_image: 'step1.jpg', step: 2, navigations: [{step:3, translate: [-0.43,-0.01,0.9], rotation: [0,140,0] }]},
{scene_image: 'step2.jpg', step: 3, navigations: [{step:4, translate: [-0.4,0.05,-0.9], rotation: [0,0,0] }]},
{scene_image: 'step3.jpg', step: 4, navigations: [{step:5, translate: [-0.55,-0.03,-0.8], rotation: [0,32,0] }]},
{scene_image: 'step4.jpg', step: 5, navigations: [{step:1, translate: [0.2,-0.03,-1], rotation: [0,20,0] }]}],
current_scene:{},
animationWidth: 0.05,
animationRadius: 50
};
}
Then we’ve changed the output of images linking them to state, previously indicated in constructor.
<View>
<Pano source={asset(this.state.current_scene['scene_image'])}
style={{
transform: [{translate: [0, 0, 0]}]
}}/>
</View>
Navigational buttons
In each scene we’ve placed transition buttons for navigation within a tour, taking data from state. Subscribing to onInput event to convey switching between scenes, binding this to it as well.
<View>
<Pano source={asset(this.state.current_scene['scene_image'])} onInput={this.onPanoInput.bind(this)}
onLoad={this.sceneOnLoad} onLoadEnd={this.sceneOnLoadEnd}
style={{ transform: [{translate: [0, 0, 0]}] }}/>
{this.state.current_scene['navigations'].map(function(item,i){
return <Mesh key={i}
style={{
layoutOrigin: [0.5, 0.5],
transform: [{translate: item['translate']},
{rotateX: item['rotation'][0]},
{rotateY: item['rotation'][1]},
{rotateZ: item['rotation'][2]}]
}}
onInput={ e => that.onNavigationClick(item,e)}>
<VrButton
style={{ width: 0.15,
height:0.15,
borderRadius: 50,
justifyContent: 'center',
alignItems: 'center',
borderStyle: 'solid',
borderColor: '#FFFFFF80',
borderWidth: 0.01
}}>
<VrButton
style={{ width: that.state.animationWidth,
height:that.state.animationWidth,
borderRadius: that.state.animationRadius,
backgroundColor: '#FFFFFFD9'
}}>
</VrButton>
</VrButton>
</Mesh>
})}
</View>
onNavigationClick(item,e){
if(e.nativeEvent.inputEvent.eventType === "mousedown" && e.nativeEvent.inputEvent.button === 0){
var new_scene = this.state.scenes.find(i => i['step'] === item.step);
this.setState({current_scene: new_scene});
postMessage({ type: "sceneChanged"})
}
}
sceneOnLoad(){
postMessage({ type: "sceneLoadStart"})
}
sceneOnLoadEnd(){
postMessage({ type: "sceneLoadEnd"})
}
this.sceneOnLoad = this.sceneOnLoad.bind(this);
this.sceneOnLoadEnd = this.sceneOnLoadEnd.bind(this);
this.onNavigationClick = this.onNavigationClick.bind(this);
Button animation
Below, we’ll display the code for navigation button animations. We’ve built animations on button increase principle, applying conventional requestAnimationFrame.
this.animatePointer = this.animatePointer.bind(this);
animatePointer(){
var delta = this.state.animationWidth + 0.002;
var radius = this.state.animationRadius + 10;
if(delta >= 0.13){
delta = 0.05;
radius = 50;
}
this.setState({animationWidth: delta, animationRadius: radius})
this.frameHandle = requestAnimationFrame(this.animatePointer);
}
componentDidMount(){
this.animatePointer();
}
componentWillUnmount(){
if (this.frameHandle) {
cancelAnimationFrame(this.frameHandle);
this.frameHandle = null;
}
}
In componentWillMount function we’ve indicated the current scene. Then we’ve also subscribed to message event for data exchange with the main thread. We do it this way due to a need to work out a React VR component in a separate thread.
In onMainWindowMessage function we only process one message with newCoordinates key. We’ll elaborate later why we do so. Similarly, we’ve subscribed to onInput event to convey arrow turns.
componentWillMount(){
window.addEventListener('message', this.onMainWindowMessage);
this.setState({current_scene: this.state.scenes[0]})
}
onMainWindowMessage(e){
switch (e.data.type) {
case 'newCoordinates':
var scene_navigation = this.state.current_scene.navigations[0];
this.state.current_scene.navigations[0]['translate'] = [e.data.coordinates.x,e.data.coordinates.y,e.data.coordinates.z]
this.forceUpdate();
break;
default:
return;
}
}
<Pano source={asset(this.state.current_scene['scene_image'])} onInput={this.onPanoInput.bind(this)}
style={{ transform: [{translate: [0, 0, 0]}] }}/>
rotatePointer(nativeEvent){
switch (nativeEvent.keyCode) {
case 38:
this.state.current_scene.navigations[0]['rotation'][1] += 4;
break;
case 39:
this.state.current_scene.navigations[0]['rotation'][0] += 4;
break;
case 40:
this.state.current_scene.navigations[0]['rotation'][2] += 4;
break;
default:
return;
}
this.forceUpdate();
}
Arrow turns are done with ↑→↓ alt keys, for Y-X-Z axes respectively.
See and download the whole index.vr.js file on Github HERE.
Client.js file
Moving further into our React VR example of virtual reality web applications, we’ve added the code below into init function. The goal is processing of ondblclick, onmousewheel and message events, where the latter is in rendering thread for message exchanges. Also, we’ve kept a link to vr and vr.player._camera objects.
window.playerCamera = vr.player._camera;
window.vr = vr;
window.ondblclick= onRendererDoubleClick;
window.onmousewheel = onRendererMouseWheel;
vr.rootView.context.worker.addEventListener('message', onVRMessage);
We’ve introduced the onVRMessage function for zoom returning to default when scenes change. Also, we have added the loader when scene change occurs.
function onVRMessage(e) {
switch (e.data.type) {
case 'sceneChanged':
if (window.playerCamera.zoom != 1) {
window.playerCamera.zoom = 1;
window.playerCamera.updateProjectionMatrix();
}
break;
case 'sceneLoadStart':
document.getElementById('loader').style.display = 'block';
break;
case 'sceneLoadEnd':
document.getElementById('loader').style.display = 'none';
break;
default:
return;
}
}
onRendererDoubleClick function for 3D-coordinates calculation and sending messages to vr component to change arrow coordinates. The get3DPoint function is custom to our web VR application and looks like this:
function onRendererDoubleClick(){
var x = 2 * (event.x / window.innerWidth) - 1;
var y = 1 - 2 * ( event.y / window.innerHeight );
var coordinates = get3DPoint(window.playerCamera, x, y);
vr.rootView.context.worker.postMessage({ type: "newCoordinates", coordinates: coordinates });
}
Switch to mouse wheel
We’ve used the onRendererMouseWheel function for switching zoom to a mouse wheel.
function onRendererMouseWheel(){
if (event.deltaY > 0 ){
if(window.playerCamera.zoom > 1) {
window.playerCamera.zoom -= 0.1;
window.playerCamera.updateProjectionMatrix();
}
}
else {
if(window.playerCamera.zoom < 3) {
window.playerCamera.zoom += 0.1;
window.playerCamera.updateProjectionMatrix();
}
}
}
Exporting coordinates
Then we’ve utilized Three.js to work with 3D-graphics. In this file we’ve only conveyed one function to export screen coordinated to world coordinates.
import * as THREE from 'three';
export function get3DPoint(camera,x,y){
var mousePosition = new THREE.Vector3(x, y, 0.5);
mousePosition.unproject(camera);
var dir = mousePosition.sub(camera.position).normalize();
return dir;
}
See and download the whole client.js file on Github HERE. There’s probably no need to explain how the cameraHelper.js file works, as it is plain simple, and you can download it as well.
Also, if you are interested in a lookalike project estimate or same additional technical details about ReactVR development - you can find some info here:

Making SVG Responsive in React

I am working on a responsive utility component, to make a few D3 components responsive in react. However I deep SVG knowledge escapes me. I have based my responsive utility on this issue on github. However it isn't quite working, All it does is render the a chart, but not at the width or height passed in but rather at a really small width and height. It also doesn't resize.
import React from 'react';
class Responsive extends React.Component{
constructor () {
super();
this.state = {
size: {
w: 0,
h: 0
}
}
}
componentDidMount () {
window.addEventListener('resize', this.fitToParentSize.bind(this));
this.fitToParentSize();
}
componentWillReceiveProps () {
this.fitToParentSize();
}
componentWillUnmount() {
window.removeEventListener('resize', this.fitToParentSize.bind(this));
}
fitToParentSize () {
let elem = this.findDOMNode(this);
let w = elem.parentNode.offsetWidth;
let h = elem.parentNode.offsetHeight;
let currentSize = this.state.size;
if (w !== currentSize.w || h !== currentSize.h) {
this.setState({
size: {
w: w,
h: h
}
});
}
}
render () {
let {width, height} = this.props;
width = this.state.size.w || 100;
height = this.state.size.h || 100;
var Charts = React.cloneElement(this.props.children, { width, height});
return Charts;
}
};
export default Responsive;
Responsive width={400} height={500}>
<XYAxis data={data3Check}
xDataKey='x'
yDataKey='y'
grid={true}
gridLines={'solid'}>
<AreaChart dataKey='a'/>
<LineChart dataKey='l' pointColor="#ffc952" pointBorderColor='#34314c'/>
</XYAxis>
</Responsive>
disclaimer: I'm the author of vx a low-level react+d3 library full of visualization components.
You could use #vx/responsive or create your own higher-order component based on withParentSize() or withWindowSize() depending on what sizing you want to respond to (I've found most situations require withParentSize()).
The gist is you create a higher-order component that takes in your chart component and it attaches/removes event listeners for when the window resizes with a debounce time of 300ms by default (you can override this with a prop) and stores the dimensions in its state. The new parent dimensions will get passed in as props to your chart as parentWidth, parentHeight or screenWidth, screenHeight and you can set your svg's width and height attributes from there or calculate your chart dimensions based on those values.
Usage:
// MyChart.js
import { withParentSize } from '#vx/responsive';
function MyChart({ parentWidth, parentHeight }) {
return (
<svg width={parentWidth} height={parentHeight}>
{/* stuff */}
</svg>
);
}
export default withParentSize(MyChart);

Resources