React Native Map (Airbnb) + Markers animation - google-maps

I want to animate the React-native-maps {Google} markers.
I tried with the animated module, but the markers do not allow complex styles.
Is there any function to modify the coordinates of the marker and give it animation?, like a:
marker.setAnimation(google.maps.Animation.BOUNCE);
I have tried with:
<MapView.Marker.Animated>
But I can not create the effect. Is there a function that edits the coordinates as an animation drop?

React native map marker is by default "not animated", it can not accept gif images, sprites, animation api and so on . . However, I was able to animate it the tough way through image transition. Here is my example:
constructor(props, context) {
super(props, context);
this.state = {
startTransition: 1,
endTransition: 4,
};
}
componentDidMount() {
this.animate();
}
animate() {
const {startTransition, endTransition} = this.state;
if(startTransition < endTransition){
let currentTransition = startTransition + 1;
this.setState({startTransition: currentTransition});
} else {
this.setState({startTransition: 1});
}
let x = setTimeout(()=>{
this.animate()
}, 500);
}
renderImg(imgTrans) {
if(imgTrans === 1) {
return require('./walk1.png');
}
if(imgTrans === 2) {
return require('./walk2.png');
}
if(imgTrans === 3) {
return require('./walk3.png');
}
if(imgTrans === 4) {
return require('./walk4.png');
}
}
render() {
const {startTransition} = this.state;
return (
<MapView.Marker
coordinate={tapCoords}
image={this.renderImg(startTransition)}
>
)
}
This is how I did the animation for now.

Related

Why does the ToolController's getPriority return 0 for my tool?

According to a prior SO answer, you can implement getPriority for a forge viewer Tool. And according to another SO answer extending the ToolInterface does not work. Hence, me not extending the ToolInterface implementing my Tool like so:
class MyCustomExtension extends Autodesk.Viewing.Extension {
constructor(viewer, options) {
super(viewer, options);
this.theiaUtil = new TheiaUtil(this);
}
getPriority() {
console.log("Theia#getPriority called! ", (this.getPriority && this.getPriority() || 0));
return 100000;
}
...
}
My tool's priority is returned as 0 in the ToolController, although it shouldn't:
function getPriority(tool)
{
return tool.getPriority instanceof Function && tool.getPriority() || 0;
}
I don't know why this function returns 0 as tool.getPriority instanceof Function returns true if I call MyCustomExtension.getPriority myself.
Note that ToolInterface is implemented like so:
function ToolInterface()
{
this.names = [ "unnamed" ];
this.getNames = function() { return this.names; };
this.getName = function() { return this.names[0]; };
this.getPriority = function() { return 0; };
this.register = function() {};
this.deregister = function() {};
this.activate = function(name, viewerApi) {};
this.deactivate = function(name) {};
this.update = function(highResTimestamp) { return false; };
this.handleSingleClick = function( event, button ) { return false; };
this.handleDoubleClick = function( event, button ) { return false; };
this.handleSingleTap = function( event ) { return false; };
this.handleDoubleTap = function( event ) { return false; };
// ...
}
Because of that, simply extending the ToolInterface class won't work because all these properties and functions added to the instance in the constructor will take precedence over your actual class methods. This is also likely the reason why you're seeing the priority value returned as zero - when you call myTool.getPriority(), you are not actually calling your getPriority method, but rather the default function which was assigned to this.getPriority in ToolInterface's constructor.
To work around this issue I would recommend explicitly deleting the corresponding fields in your class' constructor (something I explain in my blog post on implementing custom Forge Viewer tools):
class DrawTool extends Autodesk.Viewing.ToolInterface {
constructor() {
super();
this.names = ['box-drawing-tool', 'sphere-drawing-tool'];
// Hack: delete functions defined *on the instance* of the tool.
// We want the tool controller to call our class methods instead.
delete this.register;
delete this.deregister;
delete this.activate;
delete this.deactivate;
delete this.getPriority;
delete this.handleMouseMove;
delete this.handleButtonDown;
delete this.handleButtonUp;
delete this.handleSingleClick;
}
register() {
console.log('DrawTool registered.');
}
deregister() {
console.log('DrawTool unregistered.');
}
activate(name, viewer) {
console.log('DrawTool activated.');
}
deactivate(name) {
console.log('DrawTool deactivated.');
}
getPriority() {
return 42; // Or feel free to use any number higher than 0 (which is the priority of all the default viewer tools)
}
// ...
}
TL;DR: Activate the tool in button click event from a toolbar button instead of the extension's load method.
class MyExtension extends Autodesk.Viewing.Extension {
...
onToolbarCreated(toolbar) {
const MyToolName = 'My.Tool.Name'
let button = new Autodesk.Viewing.UI.Button('my-tool-button');
button.onClick = (e) => {
const controller = this.viewer.toolController;
if (controller.isToolActivated(MyToolName)) {
controller.deactivateTool(MyToolName);
button.setState(Autodesk.Viewing.UI.Button.State.INACTIVE);
} else {
controller.activateTool(MyToolName);
button.setState(Autodesk.Viewing.UI.Button.State.ACTIVE);
}
};
}
...
}
I activated the tool instantly after registering it in the Extension's load method. Petr Broz's github repo from his blog post loads the tool from a button in the toolbar. So I moved the activation of the tool to a button click in the toolbar which worked for me.

How to validation a url inside a quill editor link

I am using a quill editor with my angular8 project. On the same there is an option to add url with the help of 'link'. Could I know, is there any way to validate the url which I will enter for the 'link' textbox as shown images below. Following are my codes
quill editor module
editorConfig= {
formula: true,
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['link']
]
};
html
<quill-editor [modules]="editorConfig" [style]="{height: '200px'}"></quill-editor>
How to validate links inside the textbox which is marked on the image above.
Yeah I find a way to resolve this question
First we need two function to override the default link handler and the function of snowtooltip save
import Emitter from 'quill/core/emitter';
import { message } from 'antd';
/**
* override Snow tooltip save
*/
export function SnowTooltipSave() {
const { value } = this.textbox;
const linkValidityRegex = /^(http|https)/;
switch (this.root.getAttribute('data-mode')) {
case 'link': {
if (!linkValidityRegex.test(value)) {
message.error('链接格式错误,请输入链接 http(s)://...');
return;
}
const { scrollTop } = this.quill.root;
if (this.linkRange) {
this.quill.formatText(this.linkRange, 'link', value, Emitter.sources.USER);
delete this.linkRange;
} else {
this.restoreFocus();
this.quill.format('link', value, Emitter.sources.USER);
}
this.quill.root.scrollTop = scrollTop;
break;
}
default:
}
this.textbox.value = '';
this.hide();
}
export function SnowThemeLinkHandler(value) {
if (value) {
const range = this.quill.getSelection();
if (range == null || range.length === 0) return;
let preview = this.quill.getText(range);
if (/^\S+#\S+\.\S+$/.test(preview) && preview.indexOf('mailto:') !== 0) {
preview = `mailto:${preview}`;
}
const { tooltip } = this.quill.theme;
tooltip.save = DtysSnowTooltipSave;
tooltip.edit('link', preview);
} else {
this.quill.format('link', false);
}
}
then use these function in editor
const SnowTheme = Quill.import('themes/snow');
SnowTheme.DEFAULTS.modules.toolbar.handlers.link = SnowThemeLinkHandler;

Why are my React rendered HTML elements changing positions after refresh?

I have a react component that I am using as checkpoint to check if the user has viewed a certain section of the site.
class ContentSection extends Component {
constructor(props) {
super(props);
}
render() {
const allParagraphs = [];
for (let i = 0; i < this.props.paragraphs.length; i++) {
let p = this.props.paragraphs[i];
allParagraphs.push(
<Paragraph key={i} image={p["img"]} text={p["text"]} />
);
}
return (
<div className="cs">
<ContentSectionCheckPointContainer
uniqueIndex={this.props.uniqueIndex}
/>
<h4 className="sectionTitle">THIS IS A SECTION!!!</h4>
{allParagraphs}
</div>
);
}
}
And this is the ContentSectionCheckPointContainer
const mapDispatchToProps = dispatch => {
return {
unlock: index => dispatch(Unlock_Index_Action(index))
};
};
const mapStateToProps = state => {
return {
CheckPoints: [...state.CheckPoints]
};
};
class ContentSectionCheckPoint extends Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
this.myRect = null;
this.checkVisibility = this.checkVisibility.bind(this);
}
componentDidMount() {
this.checkVisibility();
window.addEventListener('scroll', this.checkVisibility);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.checkVisibility);
}
checkVisibility() {
if (this.myRef.current) {
let rect = this.myRef.current.getBoundingClientRect();
var viewHeight = Math.max(
document.documentElement.clientHeight,
window.innerHeight
);
let b = !(rect.bottom < 0 || rect.top - viewHeight >= 0);
if (b !== this.props.CheckPoints[this.props.uniqueIndex]) {
if (b) {
this.props.unlock(this.props.uniqueIndex);
}else{
this.props.unlock(this.props.uniqueIndex);
}
}
}
}
render() {
this.checkVisibility();
return (
<div ref={this.myRef} className="cscp">
{this.props.CheckPoints[this.props.uniqueIndex] && <p>hi</p>}
</div>
);
}
}
const ContentSectionCheckPointContainer = connect(
mapStateToProps, mapDispatchToProps)(ContentSectionCheckPoint);
As you can see I ran a visibility check on scroll, which works fine. However, I wanted to also run the visibility check immediately when the page is loaded before any scrolling occur.
It is to my understanding that componentDidMount is when React already rendered an element for the first time, so I wanted to do the check then. However, I was trying to render two ContentSection components, each containing their own check point. The latter check point for unknown reason is positioned higher than it appears on screen during componentDidMount, resulting in my visibility check returning true even though it is not visible. If I refresh the page, its position is correct again and the visibility check is fine.
This problem only seem to occur during the first time when I open up a new tab to load my code, but no longer occurs after a refresh on that tab.
Any idea why?

Cannot read property 'rotationOffset' of undefined

I am using react-vr and trying to use the json object to render image, but I'm getting an error that the browser cannot read property 'rotationOffset' of undefined. Below is my code for reference.
static defaultProps = {
portal: 'webTour.json',
} //assigning the json to a variable.
componentDidMount() {
fetch(asset(this.props.portal).uri)
.then(response => response.json())
.then(responseData => {
this.init(responseData);
})
.done
();
}
init(tourConfig) {
// Initialize the tour based on data file.
this.setState({
data: tourConfig,
locationId: null,
nextLocationId: tourConfig.firstPhotoId,
rotation: tourConfig.firstPhotoRotation + (tourConfig.photos[tourConfig.firstPhotoId].rotationOffset || 0),
});
}
render() {
//some code
const locationId = this.state.locationId;
const photoData = (locationId && this.state.date.photos[locationId]) || null;
const rotation = this.state.data.firstPhotoRotation + ((photoData && photoData.rotationOffset) || 0);
const isLoading = this.state.nextLocationId !== this.state.locationId;
return (
<Pano source = {asset(this.state.data.photos[this.state.nextLocationID].uri)} />
}
And below is my json file for reference.
{
"nave_icon": "gateway.png",
"firstPhotoID" : "112001",
"firstPhotoRotation" : 90,
"photos":{
"112001":{
"rotationOffset": 0,
"uri": "CustomPano_2.jpg",
}
}
}
What I'm trying to do is that change the background image with the objects inside the Pano. Am I missing any essential syntax? I've spent hours to figure out the problem is not working. Any help is much appreciated.

ReactJS props updating at different speeds in same component

I have a Google maps component in a React/Redux app. When you click an item from a list, it passes down an array of coordinates to render as directions from the user's current location. The props are being passed fine through react-redux mapStateToProps. I'm calling a function to generate the the polyline, this is where my problem is. The marker is generated fine inside of render, but the directions do not render until another entry is clicked. Basically it's always one step behind the current markers. So, for 2 stops, I'll have directions from current location to stop 1, but not stop 2. For 3 stops, current location to stop 1 to stop 2 will be generated, but not stop 3.
When I log out the length of the array of stops inside of render I get the expected amount, a length of 1 for 1 stop. I have tried putting the method inside of componentWillWillReceiveProps and componentWillUpdate, and both methods will log a 0 for 1 stop.
Here's the component, if relevant:
const GoogleMapComponent = React.createClass({
mixin: [PureRenderMixin],
getInitialState: function() {
return {
map: null,
maps: null,
color: 0
}
},
componentWillUpdate: function() {
console.log('LOGS ZERO HERE', this.props.tourList.length)
if (this.state.maps) {
this.calculateAndDisplayRoute(this.state.directionsService, this.state.directionsDisplay, this.props.tourList);
}
},
saveMapReferences: function(map, maps) {
let directionsDisplay = new maps.DirectionsRenderer({map, polylineOptions: {strokeColor: '#76FF03'}, suppressMarkers: true});
let directionsService = new maps.DirectionsService();
this.setState({ map, maps, directionsService, directionsDisplay });
},
generateWaypoints: function(coords) {
return coords.map((coord) => {
return { location: new this.state.maps.LatLng(coord.lat, coord.lng) };
});
},
calculateAndDisplayRoute: function(directionsService, directionsDisplay, tourStops) {
let origin = this.props.userLocation || { lat: 37.77, lng: -122.447 };
let destination = tourStops[tourStops.length - 1];
let directions = { origin, destination, travelMode: this.state.maps.TravelMode.DRIVING };
if (this.props.tourList.length > 1) {
directions.waypoints = this.generateWaypoints(tourStops);
}
if (tourStops.length > 0) {
directionsService.route(directions, (response, status) => {
if (status === this.state.maps.DirectionsStatus.OK) {
directionsDisplay.setDirections(response);
} else {
console.log('Directions request failed due to ' + status);
}
});
} else {
directionsDisplay.set('directions', null);
}
},
render: function() {
console.log('LOGS 1 HERE', this.props.tourList.length)
let markers = this.props.tourList.map((marker, idx) => {
let loc = marker.prevLoc ? marker.prevLoc : 'your current location.';
return <Marker className='point' key={idx} image={marker.poster} lat={marker.lat} lng={marker.lng} location={marker.location} price={marker.price} loc={loc} />
});
let defaultCenter = {lat: 37.762, lng: -122.4394};
let defaultZoom = 12
if (this.props.userLocation !== null) {
return (
<div className='map'>
<GoogleMap defaultCenter={defaultCenter} defaultZoom={defaultZoom} yesIWantToUseGoogleMapApiInternals={true}
onGoogleApiLoaded={({map, maps}) => {
map.setOptions({styles: mapStyles});
this.saveMapReferences(map, maps);
}} >
{markers}
<UserMarker lat={this.props.userLocation.lat} lng= {this.props.userLocation.lng} />
</GoogleMap>
</div>
);
}
return (
<div className='map'>
<GoogleMap defaultCenter={defaultCenter} defaultZoom={defaultZoom} yesIWantToUseGoogleMapApiInternals={true}
onGoogleApiLoaded={({map, maps}) => {
map.setOptions({styles: mapStyles});
this.saveMapReferences(map, maps);
}} >
{markers}
</GoogleMap>
</div>
);
}
});
function mapStateToProps(state) {
return {
tourList: state.sidebar.tourList,
userLocation: state.home.userLocation
}
}
export default connect(mapStateToProps)(GoogleMapComponent);
Figured it out, I was not passing nextProps to componentWillUpdate, so the function was always being called with the old props.
componentWillUpdate is called prior to this.props being updated. Change componentWillUpdate as follows:
componentWillUpdate: function(nextProps) {
console.log('SHOULD LOG ONE HERE', nextProps.tourList.length)
if (this.state.maps) {
this.calculateAndDisplayRoute(this.state.directionsService, this.state.directionsDisplay, nextProps.tourList);
}
}