How to use Framer Motions's when to control transition animation start - framerjs

I am trying to set display:none on a parent element once the children stagger animations have completed. My li elements fade out and the parent ul should then update to display:none
I can set a delay in the transition, but trying to tap into the when property. I have tried:
const variants = {
open: {
display: 'block',
transition: {
staggerChildren: 0.17,
delayChildren: 0.2,
}
},
closed: {
display: 'none',
transition: {
staggerChildren: 0.05,
staggerDirection: -1,
display: {
when: "afterChildren" // delay: 1 - this will work
}
}
}
};
Clearly I am getting the syntax incorrect or cannot be used as I intend.
Sandbox Demo
import * as React from "react";
import { render } from "react-dom";
import {motion, useCycle} from 'framer-motion';
const ulVariants = {
open: {
display: 'block',
visibility: 'visible',
transition: {
staggerChildren: 0.17,
delayChildren: 0.2,
}
},
closed: {
display: 'none',
transition: {
staggerChildren: 0.05,
staggerDirection: -1,
display: {
when: "afterChildren" // delay: 1 - will work
}
}
}
};
const liVariants = {
open: {
y: 0,
opacity: 1,
transition: {
y: {stiffness: 1000, velocity: -100}
}
},
closed: {
y: 50,
opacity: 0,
transition: {
y: {stiffness: 1000}
}
}
}
const Item = (props) => (
<motion.li
variants={liVariants}
>
{props.name}
</motion.li>
)
const App = () => {
const [isOpen, toggleOpen] = useCycle(false, true);
return (
<>
<button onClick={toggleOpen}>Toggle Animation</button>
<motion.ul
variants={ulVariants}
animate={isOpen ? 'open': 'closed'}
>
{Array.from(['vader', 'maul', 'ren']).map((item, index) => (
<Item key={item} {...{name: item}} />
))}
</motion.ul>
</>
);
};
render(<App />, document.getElementById("root"));

when should be a property of the transition object, not display.
This seems to work (unless I'm misunderstanding what you're trying to do):
closed: {
display: 'none',
transition: {
staggerChildren: 0.05,
staggerDirection: -1,
when: "afterChildren"
}
}
Code Sandbox

You can use
<motion.div
animate={{
transitionEnd: {
display: "none",
},
}}
/>
When animating to a non-animatable value like "block", this value will be set instantly. By setting this value within transitionEnd, this value will be set at the end of the animation.
source: https://www.framer.com/docs/component

Related

How to navigate page immediately after rendering animation?

I currently have a loading screen that renders an animation. After doing so I would like it to immediately, based on firebase.auth().onAuthStateChange, navigate the user to a specific page.
I have already implemented the animation and part of the logic. I just need the ability to navigate immediately after the first render/animation has completed.
class LoadingScreen extends Component {
state = {
opacity: new Animated.Value(0),
}
onLoad = () => {
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 1500,
delay: 1000,
useNativeDriver: true,
}).start();
}
render() {
return (
<Animated.Image
onLoad={this.onLoad}
{...this.props}
style={[
{
opacity: this.state.opacity,
transform: [
{
scale: this.state.opacity.interpolate({
inputRange: [0, 1],
outputRange: [0.85, 1],
})
},
],
},
this.props.style,
]}
/>
);
}
}
export default class App extends Component{
render()
{
return (
<View style={styles.container}>
<LoadingScreen
style={styles.image}
source= {require('../assets/images/logo.png')}
/>
</View>
)
}
checkIfLoggedIn = () => {
firebase.auth().onAuthStateChanged((user)=>
{
if(user)
{
this.props.navigation.navigate('Login');
}
else
{
this.props.navigation.navigate('Signup');
}
})
}
}
To do something on the end of the animation, you should add a callback to the start() function, so:
Pass your checkIfLoggedIn function as a prop to LoadingScreen component
<LoadingScreen
style={styles.image}
source= {require('../assets/images/logo.png')}
onAnimationEnd={this.checkIfLoggedIn}
/>
Use the function passed as a prop for the animation callback
onLoad = () => {
Animated.timing(this.state.opacity, {
toValue: 1,
duration: 1500,
delay: 1000,
useNativeDriver: true,
}).start(() => this.props.onAnimationEnd());
}

How to put shadow inside of bar chart in highcharts?

How to put shadow inside of bar chart like box-shadow inset(css) in hightcharts as image below.
Thank you. Have a good day~
enter image description here
You can use two overlap series, one with default shadow property and translate both of them by a few pixels in load event:
Highcharts.chart('container', {
chart: {
...,
events: {
load: function() {
this.series[0].points[0].graphic.attr({
translateX: -2
});
this.series[1].points[0].graphic.attr({
translateX: -2
});
}
}
},
...,
series: [{
...,
data: [100],
shadow: {
color: 'gray',
opacity: 0.8,
width: 2
}
}, {
data: [50]
}]
});
Live demo: http://jsfiddle.net/BlackLabel/b7hp0r6s/
API Reference: https://api.highcharts.com/highcharts/series.bar.shadow
Unfortunately, Highcharts doesn't have an inset shadow implemented in the core. However, it can be done by adding custom logic to Highcharts.SVGElement.prototype.shadow method. Check the code and demo posted below and let me know if something is unclear for you.
Additionally, to add a partial fill to columns with the inner shadow you have to make a custom column elements and insert them to the DOM between shadows and particular points.
Code:
function insertAfter(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
(function(H) {
H.SVGElement.prototype.shadow = function(shadowOptions, group, cutOff) {
var shadows = [],
i, shadow, element = this.element,
strokeWidth, shadowWidth, shadowElementOpacity,
// compensate for inverted plot area
transform,
elemBBox = element.getBBox(),
translateX,
translateY;
if (!shadowOptions) {
this.destroyShadows();
} else if (!this.shadows) {
shadowWidth = H.pick(shadowOptions.width, 3);
shadowElementOpacity = (shadowOptions.opacity || 0.15) /
shadowWidth;
transform = this.parentInverted ?
'(' + H.pick(shadowOptions.offsetY, 1) * -1 + ', ' +
H.pick(shadowOptions.offsetX, 1) * -1 + ')' :
'(' + H.pick(shadowOptions.offsetX, 1) + ', ' +
H.pick(shadowOptions.offsetY, 1) + ')';
if (!shadowOptions.inside) {
for (i = 1; i <= shadowWidth; i++) {
shadow = element.cloneNode(0);
strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
H.attr(shadow, {
stroke: (shadowOptions.color ||
'#000000'),
'stroke-opacity': shadowElementOpacity * i,
'stroke-width': strokeWidth,
transform: 'translate' + transform,
fill: 'none'
});
shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
if (cutOff) {
H.attr(shadow, 'height', Math.max(H.attr(shadow, 'height') - strokeWidth, 0));
shadow.cutHeight = strokeWidth;
}
if (group) {
group.element.appendChild(shadow);
} else if (element.parentNode) {
element.parentNode.insertBefore(shadow, element);
}
shadows.push(shadow);
}
} else {
for (i = shadowWidth; i >= 1; i--) {
shadow = element.cloneNode(0);
translateX = i / 2 - shadowOptions.offsetY;
translateY = i / 2 - shadowOptions.offsetX;
H.attr(shadow, {
stroke: (shadowOptions.color ||
'#000000'),
'stroke-opacity': shadowElementOpacity * (shadowWidth - i + 1),
'stroke-width': i,
transform: 'translate(' + translateX + ',' + translateY + ')',
fill: 'none'
});
H.css(shadow, {
width: elemBBox.width - i,
height: elemBBox.height - i,
});
shadow.setAttribute('class', (shadow.getAttribute('class') || '') + ' highcharts-shadow');
if (cutOff) {
H.attr(shadow, 'height', Math.max(H.attr(shadow, 'height') - strokeWidth, 0));
shadow.cutHeight = strokeWidth;
}
if (group) {
group.element.appendChild(shadow);
} else if (element.parentNode) {
insertAfter(shadow, element);
}
shadows.push(shadow);
}
}
this.shadows = shadows;
}
return this;
};
})(Highcharts)
Highcharts.chart('container', {
chart: {
type: 'column',
inverted: true,
events: {
render: function() {
var chart = this,
yAxis = chart.yAxis[0],
partialFillWidth,
elem,
bBox;
if (chart.customElements && chart.customElements.length) {
chart.customElements.forEach(custElem => {
custElem.parentNode.removeChild(custElem);
})
chart.customElements.length = 0;
} else {
chart.customElements = [];
}
chart.series[0].points.forEach(point => {
bBox = point.graphic.getBBox();
elem = point.graphic.element.cloneNode(0);
partialFillWidth = yAxis.toPixels(point.partialFill);
Highcharts.attr(elem, {
fill: point.partialFillColor,
transform: 'translate(0, ' + (bBox.height - (point.partialFill / point.y) * bBox.height) + ')'
});
Highcharts.css(elem, {
height: (point.partialFill / point.y) * bBox.height
});
insertAfter(elem, point.graphic.element);
chart.customElements.push(elem);
});
}
}
},
title: {
text: 'Efficiency Optimization by Branch'
},
xAxis: {
categories: [
'Seattle HQ',
'San Francisco',
'Tokyo'
]
},
yAxis: [{
min: 0,
title: {
text: 'Employees'
}
}, {
title: {
text: 'Profit (millions)'
},
opposite: true
}],
legend: {
shadow: false
},
tooltip: {
shared: true
},
plotOptions: {
column: {
grouping: false,
shadow: false,
borderWidth: 0,
pointPadding: 0,
groupPadding: 0
}
},
series: [{
color: '#efefef',
id: 'main',
data: [{
y: 120,
partialFill: 100,
partialFillColor: '#bbb'
}, {
y: 50,
partialFill: 10,
partialFillColor: '#bbb'
}, {
y: 70,
partialFill: 20,
partialFillColor: '#bbb'
}],
pointPadding: 0.4,
shadow: {
color: 'rgba(0, 0, 0, 0.5)',
opacity: 0.3,
width: 5,
offsetX: 0,
offsetY: 0,
inside: true
}
}]
});
<script src="https://code.highcharts.com/highcharts.js"></script>
<div id="container"></div>
Demo:
https://jsfiddle.net/BlackLabel/kvrjd48w/
API reference:
https://api.highcharts.com/highcharts/chart.events.render
https://api.highcharts.com/class-reference/Highcharts.SVGElement
https://api.highcharts.com/class-reference/Highcharts#.attr

Add widgets to existing jQuery-UI lib

I have to extend an existing project which uses version 1.10.4, and this jQuery-UI version is build without any widgets.
Now I want to use the widgets "Spinner" and "Selectmenu".
For the "Spinner"-widget: this is available for jQuery version 1.10.4.
The "Selectmenu"-widget is available from versoin 1.11.4.
Unfortunately, I can't update the current versoin of jQuery-UI, so I want to know how/if it's possible to enhance the current version with these two widgets.
Using the $.widget() you can extend or create your own custom widgets. I gathered this code from https://code.jquery.com/ui/1.11.4/jquery-ui.js and since $.ui.menu exists in 1.10.4, this mostly works. Some adjustments must be made.
I gathered the styleing from https://code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css
$(function() {
$.widget("custom.selectmenu", {
version: "1.11.4",
defaultElement: "<select>",
options: {
appendTo: null,
disabled: null,
icons: {
button: "ui-icon-triangle-1-s"
},
position: {
my: "left top",
at: "left bottom",
collision: "none"
},
width: null,
// callbacks
change: null,
close: null,
focus: null,
open: null,
select: null
},
_create: function() {
var selectmenuId = this.element.uniqueId().attr("id");
this.ids = {
element: selectmenuId,
button: selectmenuId + "-button",
menu: selectmenuId + "-menu"
};
this._drawButton();
this._drawMenu();
if (this.options.disabled) {
this.disable();
}
},
_drawButton: function() {
var that = this;
// Associate existing label with the new button
this.label = $("label[for='" + this.ids.element + "']").attr("for", this.ids.button);
this._on(this.label, {
click: function(event) {
this.button.focus();
event.preventDefault();
}
});
// Hide original select element
this.element.hide();
// Create button
this.button = $("<span>", {
"class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
tabindex: this.options.disabled ? -1 : 0,
id: this.ids.button,
role: "combobox",
"aria-expanded": "false",
"aria-autocomplete": "list",
"aria-owns": this.ids.menu,
"aria-haspopup": "true"
})
.insertAfter(this.element);
$("<span>", {
"class": "ui-icon " + this.options.icons.button
})
.prependTo(this.button);
this.buttonText = $("<span>", {
"class": "ui-selectmenu-text"
})
.appendTo(this.button);
this._setText(this.buttonText, this.element.find("option:selected").text());
this._resizeButton();
this._on(this.button, this._buttonEvents);
this.button.one("focusin", function() {
// Delay rendering the menu items until the button receives focus.
// The menu may have already been rendered via a programmatic open.
if (!that.menuItems) {
that._refreshMenu();
}
});
this._hoverable(this.button);
this._focusable(this.button);
},
_drawMenu: function() {
var that = this;
// Create menu
this.menu = $("<ul>", {
"aria-hidden": "true",
"aria-labelledby": this.ids.button,
id: this.ids.menu
});
// Wrap menu
this.menuWrap = $("<div>", {
"class": "ui-selectmenu-menu ui-front"
})
.append(this.menu)
.appendTo(this._appendTo());
// Initialize menu widget
this.menuInstance = this.menu
.menu({
role: "listbox",
select: function(event, ui) {
event.preventDefault();
// support: IE8
// If the item was selected via a click, the text selection
// will be destroyed in IE
that._setSelection();
that._select(ui.item.data("ui-selectmenu-item"), event);
},
focus: function(event, ui) {
var item = ui.item.data("ui-selectmenu-item");
// Prevent inital focus from firing and check if its a newly focused item
if (that.focusIndex != null && item.index !== that.focusIndex) {
that._trigger("focus", event, {
item: item
});
if (!that.isOpen) {
that._select(item, event);
}
}
that.focusIndex = item.index;
that.button.attr("aria-activedescendant",
that.menuItems.eq(item.index).attr("id"));
}
})
.data("ui-menu");
// Adjust menu styles to dropdown
this.menu
.addClass("ui-corner-bottom")
.removeClass("ui-corner-all");
// Don't close the menu on mouseleave
this.menuInstance._off(this.menu, "mouseleave");
// Cancel the menu's collapseAll on document click
this.menuInstance._closeOnDocumentClick = function() {
return false;
};
// Selects often contain empty items, but never contain dividers
this.menuInstance._isDivider = function() {
return false;
};
},
refresh: function() {
this._refreshMenu();
this._setText(this.buttonText, this._getSelectedItem().text());
if (!this.options.width) {
this._resizeButton();
}
},
_refreshMenu: function() {
this.menu.empty();
var item,
options = this.element.find("option");
if (!options.length) {
return;
}
this._parseOptions(options);
this._renderMenu(this.menu, this.items);
this.menuInstance.refresh();
this.menuItems = this.menu.find("li").not(".ui-selectmenu-optgroup");
item = this._getSelectedItem();
// Update the menu to have the correct item focused
this.menuInstance.focus(null, item);
this._setAria(item.data("ui-selectmenu-item"));
// Set disabled state
this._setOption("disabled", this.element.prop("disabled"));
},
open: function(event) {
if (this.options.disabled) {
return;
}
// If this is the first time the menu is being opened, render the items
if (!this.menuItems) {
this._refreshMenu();
} else {
// Menu clears focus on close, reset focus to selected item
this.menu.find(".ui-state-focus").removeClass("ui-state-focus");
this.menuInstance.focus(null, this._getSelectedItem());
}
this.isOpen = true;
this._toggleAttr();
this._resizeMenu();
this._position();
this._on(this.document, this._documentClick);
this._trigger("open", event);
},
_position: function() {
this.menuWrap.position($.extend({ of: this.button
}, this.options.position));
},
close: function(event) {
if (!this.isOpen) {
return;
}
this.isOpen = false;
this._toggleAttr();
this.range = null;
this._off(this.document);
this._trigger("close", event);
},
widget: function() {
return this.button;
},
menuWidget: function() {
return this.menu;
},
_renderMenu: function(ul, items) {
var that = this,
currentOptgroup = "";
$.each(items, function(index, item) {
if (item.optgroup !== currentOptgroup) {
$("<li>", {
"class": "ui-selectmenu-optgroup ui-menu-divider" +
(item.element.parent("optgroup").prop("disabled") ?
" ui-state-disabled" :
""),
text: item.optgroup
})
.appendTo(ul);
currentOptgroup = item.optgroup;
}
that._renderItemData(ul, item);
});
},
_renderItemData: function(ul, item) {
return this._renderItem(ul, item).data("ui-selectmenu-item", item);
},
_renderItem: function(ul, item) {
var li = $("<li>");
if (item.disabled) {
li.addClass("ui-state-disabled");
}
this._setText(li, item.label);
return li.appendTo(ul);
},
_setText: function(element, value) {
if (value) {
element.text(value);
} else {
element.html(" ");
}
},
_move: function(direction, event) {
var item, next,
filter = ".ui-menu-item";
if (this.isOpen) {
item = this.menuItems.eq(this.focusIndex);
} else {
item = this.menuItems.eq(this.element[0].selectedIndex);
filter += ":not(.ui-state-disabled)";
}
if (direction === "first" || direction === "last") {
next = item[direction === "first" ? "prevAll" : "nextAll"](filter).eq(-1);
} else {
next = item[direction + "All"](filter).eq(0);
}
if (next.length) {
this.menuInstance.focus(event, next);
}
},
_getSelectedItem: function() {
return this.menuItems.eq(this.element[0].selectedIndex);
},
_toggle: function(event) {
this[this.isOpen ? "close" : "open"](event);
},
_setSelection: function() {
var selection;
if (!this.range) {
return;
}
if (window.getSelection) {
selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(this.range);
// support: IE8
} else {
this.range.select();
}
// support: IE
// Setting the text selection kills the button focus in IE, but
// restoring the focus doesn't kill the selection.
this.button.focus();
},
_documentClick: {
mousedown: function(event) {
if (!this.isOpen) {
return;
}
if (!$(event.target).closest(".ui-selectmenu-menu, #" + this.ids.button).length) {
this.close(event);
}
}
},
_buttonEvents: {
// Prevent text selection from being reset when interacting with the selectmenu (#10144)
mousedown: function() {
var selection;
if (window.getSelection) {
selection = window.getSelection();
if (selection.rangeCount) {
this.range = selection.getRangeAt(0);
}
// support: IE8
} else {
this.range = document.selection.createRange();
}
},
click: function(event) {
this._setSelection();
this._toggle(event);
},
keydown: function(event) {
var preventDefault = true;
switch (event.keyCode) {
case $.ui.keyCode.TAB:
case $.ui.keyCode.ESCAPE:
this.close(event);
preventDefault = false;
break;
case $.ui.keyCode.ENTER:
if (this.isOpen) {
this._selectFocusedItem(event);
}
break;
case $.ui.keyCode.UP:
if (event.altKey) {
this._toggle(event);
} else {
this._move("prev", event);
}
break;
case $.ui.keyCode.DOWN:
if (event.altKey) {
this._toggle(event);
} else {
this._move("next", event);
}
break;
case $.ui.keyCode.SPACE:
if (this.isOpen) {
this._selectFocusedItem(event);
} else {
this._toggle(event);
}
break;
case $.ui.keyCode.LEFT:
this._move("prev", event);
break;
case $.ui.keyCode.RIGHT:
this._move("next", event);
break;
case $.ui.keyCode.HOME:
case $.ui.keyCode.PAGE_UP:
this._move("first", event);
break;
case $.ui.keyCode.END:
case $.ui.keyCode.PAGE_DOWN:
this._move("last", event);
break;
default:
this.menu.trigger(event);
preventDefault = false;
}
if (preventDefault) {
event.preventDefault();
}
}
},
_selectFocusedItem: function(event) {
var item = this.menuItems.eq(this.focusIndex);
if (!item.hasClass("ui-state-disabled")) {
this._select(item.data("ui-selectmenu-item"), event);
}
},
_select: function(item, event) {
var oldIndex = this.element[0].selectedIndex;
// Change native select element
this.element[0].selectedIndex = item.index;
this._setText(this.buttonText, item.label);
this._setAria(item);
this._trigger("select", event, {
item: item
});
if (item.index !== oldIndex) {
this._trigger("change", event, {
item: item
});
}
this.close(event);
},
_setAria: function(item) {
var id = this.menuItems.eq(item.index).attr("id");
this.button.attr({
"aria-labelledby": id,
"aria-activedescendant": id
});
this.menu.attr("aria-activedescendant", id);
},
_setOption: function(key, value) {
if (key === "icons") {
this.button.find("span.ui-icon")
.removeClass(this.options.icons.button)
.addClass(value.button);
}
this._super(key, value);
if (key === "appendTo") {
this.menuWrap.appendTo(this._appendTo());
}
if (key === "disabled") {
this.menuInstance.option("disabled", value);
this.button
.toggleClass("ui-state-disabled", value)
.attr("aria-disabled", value);
this.element.prop("disabled", value);
if (value) {
this.button.attr("tabindex", -1);
this.close();
} else {
this.button.attr("tabindex", 0);
}
}
if (key === "width") {
this._resizeButton();
}
},
_appendTo: function() {
var element = this.options.appendTo;
if (element) {
element = element.jquery || element.nodeType ?
$(element) :
this.document.find(element).eq(0);
}
if (!element || !element[0]) {
element = this.element.closest(".ui-front");
}
if (!element.length) {
element = this.document[0].body;
}
return element;
},
_toggleAttr: function() {
this.button
.toggleClass("ui-corner-top", this.isOpen)
.toggleClass("ui-corner-all", !this.isOpen)
.attr("aria-expanded", this.isOpen);
this.menuWrap.toggleClass("ui-selectmenu-open", this.isOpen);
this.menu.attr("aria-hidden", !this.isOpen);
},
_resizeButton: function() {
var width = this.options.width;
if (!width) {
width = this.element.show().outerWidth();
this.element.hide();
}
this.button.outerWidth(width);
},
_resizeMenu: function() {
this.menu.outerWidth(Math.max(
this.button.outerWidth(),
// support: IE10
// IE10 wraps long text (possibly a rounding bug)
// so we add 1px to avoid the wrapping
this.menu.width("").outerWidth() + 1
));
},
_getCreateOptions: function() {
return {
disabled: this.element.prop("disabled")
};
},
_parseOptions: function(options) {
var data = [];
options.each(function(index, item) {
var option = $(item),
optgroup = option.parent("optgroup");
data.push({
element: option,
index: index,
value: option.val(),
label: option.text(),
optgroup: optgroup.attr("label") || "",
disabled: optgroup.prop("disabled") || option.prop("disabled")
});
});
this.items = data;
},
_destroy: function() {
this.menuWrap.remove();
this.button.remove();
this.element.show();
this.element.removeUniqueId();
this.label.attr("for", this.ids.element);
}
});
$("#spinner").spinner();
$("#speed").selectmenu();
});
.ui-selectmenu-menu {
padding: 0;
margin: 0;
position: absolute;
top: 0;
left: 0;
display: none;
}
.ui-selectmenu-menu .ui-menu {
overflow: auto;
/* Support: IE7 */
overflow-x: hidden;
padding-bottom: 1px;
}
.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
font-size: 1em;
font-weight: bold;
line-height: 1.5;
padding: 2px 0.4em;
margin: 0.5em 0 0 0;
height: auto;
border: 0;
}
.ui-selectmenu-open {
display: block;
}
.ui-selectmenu-button {
display: inline-block;
overflow: hidden;
position: relative;
text-decoration: none;
cursor: pointer;
}
.ui-selectmenu-button span.ui-icon {
right: 0.5em;
left: auto;
margin-top: -8px;
position: absolute;
top: 50%;
}
.ui-selectmenu-button span.ui-selectmenu-text {
text-align: left;
padding: 0.4em 2.1em 0.4em 1em;
display: block;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.10.4/themes/smoothness/jquery-ui.css">
<script src="https://code.jquery.com/ui/1.10.4/jquery-ui.js" integrity="sha256-tp8VZ4Y9dg702r7D6ynzSavKSwB9zjariSZ4Snurvmw=" crossorigin="anonymous"></script>
<p>
<label for="spinner">Select a value:</label>
<input id="spinner" name="value">
</p>
<label for="speed">Select a speed</label>
<select name="speed" id="speed">
<option>Slower</option>
<option>Slow</option>
<option selected="selected">Medium</option>
<option>Fast</option>
<option>Faster</option>
</select>
The first issue, 1.11.4 makes use of .menu('instance') which is not available to 1.10.4. In the code above, this was used on Line 145, and can be reverted to .data("ui-menu"); to compensate.
Second, when selecting an item, it triggered an error as item was undefined. This is alsos related to the above issue. Need to work on it more. Work in progress.

Add tabs into a React Native Maps

I want to add tabs at the bottom of my home screen but I don't manage how to do it.
I want two tabs like "Map" (for my homepage) and "Settings". I don't know how to create that, I tried to add some codes inside but it's not working. Do you have ideas of what I'm doing wrong?
Do I need to add these codes inside ?
class HomeScreen extends React.Component {
render() {
return (
class SettingsScreen extends React.Component {
render() {
return (
I also tried to add this code at the bottom:
const TabNavigator = createBottomTabNavigator({
MAP: { screen: HomeScreen },
SETTINGS: { screen: SettingsScreen },
});
export default createAppContainer(TabNavigator);
Here is my code:
import React, { Component } from 'react';
import { StyleSheet, Text, View, Animated, Image, Dimensions } from "react-native";
import { Components, MapView } from 'expo';
const Images = [
{ uri: "https://images.unsplash.com/photo-1555706655-6dd427c11735?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" },
{ uri: "https://images.unsplash.com/photo-1555706741-8f39aa887cf7?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" },
{ uri: "https://images.unsplash.com/photo-1555706741-fade7dd756a9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" },
{ uri: "https://images.unsplash.com/photo-1555706742-67a1170e528d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80" }
]
const { width, height } = Dimensions.get("window");
const CARD_HEIGHT = height / 5;
const CARD_WIDTH = CARD_HEIGHT - 50;
export default class screens extends Component {
state = {
markers: [
{
coordinate: {
latitude: 41.414494,
longitude: 2.152695,
},
title: "Parc Güell",
description: "One of the best view in Barcelona. ",
image: Images[0],
},
{
coordinate: {
latitude: 41.403706,
longitude: 2.173504,
},
title: "Sagrada Familia",
description: "This is the second best place in Portland",
image: Images[1],
},
{
coordinate: {
latitude: 41.395382,
longitude: 2.161961,
},
title: "Casa Milà",
description: "This is the third best place in Portland",
image: Images[2],
},
{
coordinate: {
latitude: 41.381905,
longitude: 2.178185,
},
title: "Gothic Quarter",
description: "This is the fourth best place in Portland",
image: Images[3],
},
],
region: {
latitude: 41.390200,
longitude: 2.154007,
latitudeDelta: 0.04864195044303443,
longitudeDelta: 0.040142817690068,
},
};
componentWillMount() {
this.index = 0;
this.animation = new Animated.Value(0);
}
componentDidMount() {
// We should detect when scrolling has stopped then animate
// We should just debounce the event listener here
this.animation.addListener(({ value }) => {
let index = Math.floor(value / CARD_WIDTH + 0.3); // animate 30% away from landing on the next item
if (index >= this.state.markers.length) {
index = this.state.markers.length - 1;
}
if (index <= 0) {
index = 0;
}
clearTimeout(this.regionTimeout);
this.regionTimeout = setTimeout(() => {
if (this.index !== index) {
this.index = index;
const { coordinate } = this.state.markers[index];
this.map.animateToRegion(
{
...coordinate,
latitudeDelta: this.state.region.latitudeDelta,
longitudeDelta: this.state.region.longitudeDelta,
},
350
);
}
}, 10);
});
}
render() {
const interpolations = this.state.markers.map((marker, index) => {
const inputRange = [
(index - 1) * CARD_WIDTH,
index * CARD_WIDTH,
((index + 1) * CARD_WIDTH),
];
const scale = this.animation.interpolate({
inputRange,
outputRange: [1, 2.5, 1],
extrapolate: "clamp",
});
const opacity = this.animation.interpolate({
inputRange,
outputRange: [0.35, 1, 0.35],
extrapolate: "clamp",
});
return { scale, opacity };
});
return (
<View style={styles.container}>
<MapView
ref={map => this.map = map}
initialRegion={this.state.region}
style={styles.container}
>
{this.state.markers.map((marker, index) => {
const scaleStyle = {
transform: [
{
scale: interpolations[index].scale,
},
],
};
const opacityStyle = {
opacity: interpolations[index].opacity,
};
return (
<MapView.Marker key={index} coordinate={marker.coordinate}>
<Animated.View style={[styles.markerWrap, opacityStyle]}>
<Animated.View style={[styles.ring, scaleStyle]} />
<View style={styles.marker} />
</Animated.View>
</MapView.Marker>
);
})}
</MapView>
<Animated.ScrollView
horizontal
scrollEventThrottle={1}
showsHorizontalScrollIndicator={false}
snapToInterval={CARD_WIDTH}
onScroll={Animated.event(
[
{
nativeEvent: {
contentOffset: {
x: this.animation,
},
},
},
],
{ useNativeDriver: true }
)}
style={styles.scrollView}
contentContainerStyle={styles.endPadding}
>
{this.state.markers.map((marker, index) => (
<View style={styles.card} key={index}>
<Image
source={marker.image}
style={styles.cardImage}
resizeMode="cover"
/>
<View style={styles.textContent}>
<Text numberOfLines={1} style={styles.cardtitle}>{marker.title}</Text>
<Text numberOfLines={1} style={styles.cardDescription}>
{marker.description}
</Text>
</View>
</View>
))}
</Animated.ScrollView>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
scrollView: {
position: "absolute",
bottom: 30,
left: 0,
right: 0,
paddingVertical: 10,
},
endPadding: {
paddingRight: width - CARD_WIDTH,
},
card: {
padding: 10,
elevation: 2,
backgroundColor: "#FFF",
marginHorizontal: 10,
shadowColor: "#000",
shadowRadius: 5,
shadowOpacity: 0.3,
shadowOffset: { x: 2, y: -2 },
height: CARD_HEIGHT,
width: CARD_WIDTH,
overflow: "hidden",
},
cardImage: {
flex: 3,
width: "100%",
height: "100%",
alignSelf: "center",
},
textContent: {
flex: 1,
},
cardtitle: {
fontSize: 12,
marginTop: 5,
fontWeight: "bold",
},
cardDescription: {
fontSize: 12,
color: "#444",
},
markerWrap: {
alignItems: "center",
justifyContent: "center",
},
marker: {
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: "rgba(130,4,150, 0.9)",
},
ring: {
width: 24,
height: 24,
borderRadius: 12,
backgroundColor: "rgba(130,4,150, 0.3)",
position: "absolute",
borderWidth: 1,
borderColor: "rgba(130,4,150, 0.5)",
},
});
create a new file for tab navigation and add the following code:
(I imported your map component as screens)
import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator, createBottomTabNavigator } from 'react-navigation';
import TabBarIcon from '../components/TabBarIcon';
import screens from '../screens/HomeScreen';
import SettingsScreen from '../screens/SettingsScreen';
const HomeStack = createStackNavigator({
Home: screens,
});
HomeStack.navigationOptions = {
tabBarLabel: 'Home',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={
Platform.OS === 'ios'
? `ios-information-circle${focused ? '' : '-outline'}`
: 'md-information-circle'
}
/>
),
};
const SettingsStack = createStackNavigator({
Settings: SettingsScreen,
});
SettingsStack.navigationOptions = {
tabBarLabel: 'Settings',
tabBarIcon: ({ focused }) => (
<TabBarIcon
focused={focused}
name={Platform.OS === 'ios' ? 'ios-options' : 'md-options'}
/>
),
};
export default createBottomTabNavigator({
HomeStack,
SettingsStack,
});

How can I close a jquery q tip balloon after some seconds automatically?

I am using qtip plug in to show balloon conversation on my page. i can load the balloon, but i am not seeing any option to close it automatically after some seconds.
This is how i am using qtip -
$('#ShowBalloon')
.click(function()
{
if($("#content a").data("qtip")) $("#content a").qtip("destroy");
$("#content a").html("") // Set the links HTML to the current opposite corner
.qtip({
content: { text: 'You have 1 new message.' },
position: {
corner: {
tooltip: 'bottomRight',
target: 'topRight'
}
},
show: {
when: false,
ready: true,
effect: { type: 'fade' },
length: 2000
},
hide: { when: 'inactive', delay: 1000 },
style: {
border: {
width: 1,
radius: 7,
color : "#00AFF0"
},
title: { 'color': 'red', 'overflow': 'hidden' },
width: 300,
color:'White',
background: '#00AFF0',
padding: 10,
textAlign: 'center',
tip: true,
}
});
});

Resources