I cannot seem to figure out how to smoothly animate back to the originator of a hero animation. By that I mean, I have paper-card with a bunch of html (img, text, ect) on it, which I can "hero" into another element fine; but I'd like to be able to "anti-hero" back to the (much smaller) paper-card smoothly. My attempts only produce very distorted backwards transitions. The effect I'm trying to imitate is from Google's 2015 IO under the "Featured Sections". Google displays a grid of thumbnails, that when clicked, hero into youtube videos. Pressing the back arrow anti-heros back to the Featured Sections grid...smoothly. Any thoughts?
I'm sorry for the code blocks, I don't have enough reputation to display something.
My animationConfig is
animationConfig: {
value: function() {
return {
'entry': [{
name: 'cascaded-animation',
animation: 'scale-up-animation'
},
{
name: 'hero-animation',
id: 'hero',
toPage: this
}],
'exit': [{
name: 'cascaded-animation',
animation: 'scale-down-animation'
},
{
name: 'hero-animation',
id: 'hero',
fromPage: this
}]
}
}
}
And when a tap event is fired by clicking on an item, I fade out all remaining items and hero the clicked item.
_onItemTap: function(event) {
var nodes = this.$.scrollUp.children;
var nodesToScale = [];
for(var node, index = 0; node = nodes[index]; index++) {
if (node !== event.detail.item) {
nodesToScale.push(node);
}
}
this.animationConfig['entry'][0].nodes = nodesToScale;
this.animationConfig['exit'][0].nodes = nodesToScale;
this.sharedElements = {'hero': event.detail.item};
this.fire('feed-item-tap', {item: event.detail.item, data: event.detail.data});
}
This renders just fine. Element2's innerHTML is faded in upon entry in order to appear more graceful.
animationConfig: {
value: function() {
return {
'entry': [{
name: 'cascaded-animation',
animation: 'fade-in-animation',
nodes: [this.$.bio, this.$.pic],
timing: {delay: 500, duration: 2000}
},
{
name: 'hero-animation',
id: 'hero',
toPage: this
}],
'exit': [{
name: 'hero-animation',
id: 'hero',
fromPage: this
}]
}
}
}
sharedElements: {
value: function() {
return {
'hero': this.$.more_details
}
}
}
Again, the animations do occur both ways, but the hero from element2 back to element1 does not mimic the behavior on Google's IO site.
You are applying two animations on entry with cascading and delay while at the same time playing the hero animation.
Try to make it simpler using the hero animation only. The animation on Google's IO page looks like a simple hero.
Like this:
animationConfig: {
value: function() {
return {
'entry': {
name: 'hero-animation',
id: 'hero',
toPage: this
},
'exit': {
name: 'hero-animation',
id: 'hero',
fromPage: this
}
}
}
},
sharedElements: {
value: function() {
return {
'hero': this.$.more_details
}
}
}
Related
I want to add new Icon for images I add on canvas, just like mentioned in following post:
Add remove icon on image in canvas HTML5 and Fabric js
$('#remove').on('click', function(){
canvas.getActiveObject().remove();
});
canvas.on('object:selected', function(o) {
if (o.target.isType('image')) {
$('#remove').show();
}
});
canvas.on('selection:cleared', function() {
$('#remove').hide();
});
But, this solution can not work for me. I want to achieve something like done in following code:
http://jsfiddle.net/tornado1979/0fbefh52/6/
Here, I want to display any custom Image based on my code conditions.
Is there any way to achieve this.
Thanks
Thanks #Durga,
The link https://github.com/pixolith/fabricjs-customise-controls-extension has solved my problem.
Following is the way to customise the control options:
fabric.Canvas.prototype.customiseControls({
tl: {
action: 'rotate',
cursor: 'cow.png'
},
tr: {
action: 'scale'
},
bl: {
action: 'remove',
cursor: 'pointer'
},
br: {
action: 'moveUp',
cursor: 'pointer'
},
mb: {
action: 'moveDown',
cursor: 'pointer'
},
mt: {
action: {
'rotateByDegrees': 45
}
},
mr: {
action: function( e, target ) {
target.set( {
left: 200
} );
canvas.renderAll();
}
},
// only is hasRotatingPoint is not set to false
mtr: {
action: 'rotate',
cursor: 'cow.png'
},
}, function() {
canvas.renderAll();
} );
I have a nested tabNavigator inside of another tabNavigator, and I'm trying to get the inner tabNavigator's tabBar to be hidden. (The one below that shows "Map" and "list"). I'd like to keep the main tabNavigator which reads "Map Favorites Add a Site More".
The code which is rendering it this way is below:
const MainNavigator = StackNavigator({
login: {
screen: LoginScreen
},
main: {
screen: TabNavigator({
search: {
screen: TabNavigator({
map: {
screen: MapScreen
},
list: {
screen: ListScreen
}
})
},
favorites: {screen: FavoritesScreen},
addSite: {screen: AddSiteScreen},
more: {screen: MoreScreen}
})
},
filter: {
screen: FilterScreen,
navigationOptions: {
tabBarVisible: false
}
}
}, {
lazy: true
});
I've tried adding
navigationOptions: {
tabBarVisible: false
}
to the search item as shown below:
search: {
screen: TabNavigator({
map: {
screen: MapScreen
},
list: {
screen: ListScreen
}
},
navigationOptions: {
tabBarVisible: false
})
}
but it ends up hiding the outermost TabNavigator (the one which reads "Map Favorites Add a Site More") instead of the inner one as I'd expect. (Image below)
Finally, out of ideas and thinking maybe it needs to be nested in as far as possible, I've also tried adding the
navigationOptions: {
tabBarVisible: false
}
to the innermost map and list items as such:
search: {
screen: TabNavigator({
map: {
screen: MapScreen,
navigationOptions: {
tabBarVisible: false
}
},
list: {
screen: ListScreen,
navigationOptions: {
tabBarVisible: false
}
}
})
}
but the result of this is hiding both of the TabNavigators and there are none at all. Am I missing something simple on how to achieve this?
Thanks
You are correct in adding the navigationOptions with a property of tabBarVisible: false. However, you want to add it as a property to the tabNavigator, not to the screen itself like so:
search: {
screen: TabNavigator({
map: {
screen: MapScreen,
navigationOptions: {
tabBarVisible: false
}
},
list: {
screen: ListScreen
}
}, navigationOptions: {
tabBarVisible: false
});
}
One thing I want to point out is that lazy: true was deprecated in react-navigation version 23, so unless you are on version 22 or below that won't do anything.
I never ended up finding a good answer to this question, and it seems like it might be a limitation of the library.
As a workaround (which works just as well), I decided instead of having three distinct screens: SearchScreen, MapScreen, and ListScreen, I just went down to only having one screen SearchScreen, and when that screen renders, it calls a component to render inside of it.
The navigation portion is now much flatter and looks like this:
main: {
screen: TabNavigator({
search: {screen: SearchScreen},
favorites: {screen: FavoritesScreen},
addSite: {screen: AddSiteScreen},
more: {screen: MoreScreen}
})
}
Then inside of the SearchScreen, I just render the components (instead of treating them as their own distinct screens)
renderSearchScreen = () => {
const {viewStyle, lastKnownRegion, mapLoaded, sites} = this.props;
if (viewStyle === map.SearchOptions.MAP) {
return (
<SearchMap
lastKnownRegion={lastKnownRegion}
mapLoaded={mapLoaded}
updateRegion={this.props.updateRegion}
sites={sites}
/>
);
} else {
return (
<SearchList
sites={sites}
/>
);
}
};
After these changes, it's worked fine with no issues. I suppose it's also cleaner, and more logical from an architecture standpoint that Map and List be components that are nested and rendered instead of them also being distinct screens.
Hopefully this can help anyone else who runs into a similar issue with nested TabNavigators!
i have custom colors for regions and custom images for marker icons. Hovering, clicking on markers changes everytjing like i want but... How to make one marker, marked after loading a map, i cant find solution. I've been trying to click the marker icon with jquery, finding by element attribute, the click worked (according to the console log), but nothing changed on the map.
https://jsfiddle.net/6ss2eahr/7/
$(document).ready(function () {
var markers = [
{ latLng: [54.5039433, 18.3233958], name: 'Gdynia', region: 'PL-PM' },
{ latLng: [51.7472675, 18.0070145], name: 'Kalisz', region: 'PL-WP' },
{ latLng: [50.2138079, 18.8671087], name: 'Katowice', region: 'PL-SL' },
{ latLng: [50.8541274, 20.5456014], name: 'Kielce', region: 'PL-SK' }
];
var last_poi;
$('#map-pl').vectorMap({
map: 'pl_merc',
backgroundColor: '#fff',
zoomButtons: false,
zoomOnScroll: false,
regionsSelectable: false,
regionsSelectableOne: true,
markersSelectable: true,
markersSelectableOne: true,
markers: markers,
markerStyle: {
initial: {
image: 'https://www.royalparks.org.uk/_media/images/map_icons/find-my-location-icon.png'
},
hover: {
image: 'http://tiltedkilt.com/wp-content/themes/base/library/images/pin-small-icon.png',
cursor: 'pointer'
},
selected: {
image: 'http://tiltedkilt.com/wp-content/themes/base/library/images/pin-small-icon.png'
},
selectedHover: {
image: 'http://tiltedkilt.com/wp-content/themes/base/library/images/pin-small-icon.png'
}
},
regionStyle: {
hover: { fill: '#fdefc9' },
initial: { stroke: "white", "stroke-width": 1, fill: "#fcf8ed" },
selected: { fill: "#ffcc39" }
},
onMarkerClick: function (event, id) {
var mapObject = $('#map-pl').vectorMap('get', 'mapObject');
mapObject.clearSelectedRegions();
mapObject.setSelectedRegions(markers[id].region);
last_poi = id;
},
onMarkerOver: function (event, id) {
var mapObject = $('#map-pl').vectorMap('get', 'mapObject');
mapObject.clearSelectedRegions();
if (last_poi) {
mapObject.setSelectedRegions(markers[last_poi].region);
}
mapObject.setSelectedRegions(markers[id].region);
},
onMarkerOut: function (event, id) {
var mapObject = $('#map-pl').vectorMap('get', 'mapObject');
mapObject.clearSelectedRegions();
if (last_poi) {
mapObject.setSelectedRegions(markers[last_poi].region);
}
},
onRegionTipShow: function (e, label, code) {
e.preventDefault();
}
});
});
All the functions getSelectedMarkers, setSelectedRegions, and so on can handle array of values, so the solution is pretty easy to dynamically select one or more Marker and the corresponding Region:
var mapObject = $('#map-pl').vectorMap('get', 'mapObject');
// select Gdynia by index
var selectedMarkers = [0],
selectedRegions = [];
selectedMarkers.forEach(function(item) {
selectedRegions.push(mapObject.markers[item].config.region);
});
mapObject.setSelectedMarkers(selectedMarkers);
mapObject.setSelectedRegions(selectedRegions);
Your can remove the whole logic to keep track of the marker index using last_poi, which is causing the deselection in onMarkerOut and replace with the above function to get the selected Region directly from the mapObject.
I am new to Vega and Vega-Lite. I am creating a simple bar chart using Vega-Lite but I am not able to add any event listeners e.g. "hover".
I want to hover a bar and change the color of the bar.
If you're using Vega-Embed, it returns a promise with a reference to the view which allows you to use addEventListener - explained in the docs here.
Here is an example:
const width = 600
const color = blue
embed(element, {
$schema: 'https://vega.github.io/schema/vega-lite/3.0.0-rc6.json',
data: { 'values': data },
mark: {
type: 'line',
color,
point: {
color,
}
},
width,
height: width / 2,
encoding: {
'x': {
field: 'label',
type: 'temporal',
},
'y': {
field: 'value',
type: 'quantitative',
},
}
}).then(({spec, view}) => {
view.addEventListener('mouseover', function (event, item) {
console.log(item.datum)
})
})
I want to override the image plugin in CKeditor. When I right click on an image I want to open my own dialog. Can anyone point me in the right direction. I've done a basic plugin which I copied from the CKeditor site - How do I swap this to replace the image editor.
CKEDITOR.plugins.add('myplugin',
{
init: function (editor) {
editor.addCommand('mydialog', new CKEDITOR.dialogCommand('mydialog'));
if (editor.contextMenu) {
editor.addMenuGroup('mygroup', 10);
editor.addMenuItem('My Dialog',
{
label: 'Open dialog',
command: 'mydialog',
group: 'mygroup'
});
editor.contextMenu.addListener(function (element) {
return { 'My Dialog': CKEDITOR.TRISTATE_OFF };
});
}
CKEDITOR.dialog.add('mydialog', function (api) {
// CKEDITOR.dialog.definition
var dialogDefinition =
{
title: 'Sample dialog',
minWidth: 390,
minHeight: 130,
contents: [
{
id: 'tab1',
label: 'Label',
title: 'Title',
expand: true,
padding: 0,
elements:
[
{
type: 'html',
html: '<p>This is some sample HTML content.</p>'
},
{
type: 'textarea',
id: 'textareaId',
rows: 4,
cols: 40
}
]
}
],
buttons: [CKEDITOR.dialog.okButton, CKEDITOR.dialog.cancelButton],
onOk: function () {
// "this" is now a CKEDITOR.dialog object.
// Accessing dialog elements:
var textareaObj = this.getContentElement('tab1', 'textareaId');
alert("You have entered: " + textareaObj.getValue());
}
};
return dialogDefinition;
});
}
});
Hi the reason I wanted to do this was that we have our image editor control which for "usability" reasons we need to carry on using. It gets used in different bits of the site and two dialogs would confuse people. In summary what I did was
Remove the image plugin CKEDITOR.config.removePlugins = 'image, forms, div,flash,iframe,table';
Add extra plugins extraPlugins: 'tinsertimage,teditimage,teditlink,tinsertlink,teditimagelink' on creating the CKEditor
In the plugin run some JS which intercept the right click on the image
CKEDITOR.plugins.add('teditimage',
{
init: function (editor) {
editor.addCommand('tEditImage',
{
exec: function (editor) {
//This opens the custom editor
ZWSInlineEditor.openImageProperties(editor, false);
}
});
if (editor.addMenuItem) {
// A group menu is required
// order, as second parameter, is not required
editor.addMenuGroup('gImage');
// Create a manu item
editor.addMenuItem('gEditImageItem', {
label: 'Edit Image Properties',
command: 'tEditImage',
group: 'gImage'
});
}
if (editor.contextMenu) {
editor.contextMenu.addListener(function (element, selection) {
// Get elements parent, strong parent first
var parents = element.getParents("img");
// Check if it's strong
if (parents[0].getName() != "img")
return null; // No item
return { gEditImageItem: CKEDITOR.TRISTATE_ON };
});
}
}
});
I don't understand what's the point in what you're doing (or please explain us). Maybe you should rather customize dialogs than do things from scratch?