I have events with a "buffer" time before or after like "prep work" or "driving time". I'm trying to figure out how to display this. Some pseudo code of my data:
{
start: 11am,
end: 11:30am,
preptime: 5 minutes
}
The ideal thing would be to show an event that starts at 10:55, but with a different style for those first 5 minutes. Can you think of any way to accomplish this?
If I understood your question, this will subtract prep time from start of event and shade it (percentage) differently than rest of event. Tested in Firefox 54, Chrome 58, Edge, IE11.
https://jsfiddle.net/wp3nyax7/
$(function() {
var preptime = 'preptime'; /* name of property that holds prep time (minutes!) */
$('#calendar').fullCalendar({
events: [{
title: 'Event 1 has prep time',
start: moment(),
end: moment().add(30, 'minutes'),
preptime: 5
}, {
title: 'Event 2 no prep',
start: moment().add(1, 'hour'),
end: moment().add(1.5, 'hour')
}],
eventRender: function(event, element, view) {
// if there is a prep time, calculate how much to shade and make gradient for it
if (event.hasOwnProperty(preptime)) {
var prep = event[preptime];
var length = event.end.diff(event.start, 'minutes') - prep;
var ppct = (prep / length).toFixed(2) * 100;
makeGradients(element, ppct);
}
},
/* subtract prep time (minutes!) from start of event */
eventDataTransform: function(eventData) {
if (eventData.hasOwnProperty(preptime)) {
eventData.start.subtract(eventData[preptime], 'minutes');
}
return eventData;
}
});
function makeGradients(element, ppct) {
/* gradient info found via http://gradcolor.com/css3-gradient.php */
/* All these prefixed editions may not be necessary? Didn't bother to find out */
var prefixes = ['', '-moz-', '-ms-', '-o-', '-webkit-'];
var color1 = '#992222',
color2 = '#229922';
var grad = 'linear-gradient(left, {color1} {pct}%, {color2} {pct}%)'
.replace('{color1}', color1)
.replace('{color2}', color2)
.replace(/{pct}/g, ppct);
$.each(prefixes, function(i, v) {
element.css('background-image', v + grad);
});
/* also -webkit-gradient(linear, left bottom, right bottom, color-stop(%,color1), color-stop(%, color2)) */
}
});
Thank you for the ideas! #smcd had the solution I needed then I started to better understand the data I've got and had to revise my thinking a bit. The gradient idea allowed the event to remain intact and be resized and dragged which is great.
The change in my data meant that the buffer time isn't a part of the start and end times. Instead it's an additional field. So a 9am - 10am appointment with a 5 minute buffer still needs to be read and written back as 9-10 rather than 8:55 - 10. This matches the customer experience as well since they are thinking of 9am - 10am events. They do need to see that there's additional time required.
My solution was to add classes to the events objects like: .buffer-5, .buffer-10, .buffer-15 to support 5 minute intervals. From there I use the slotWidth value to determine the size to display. Using :before I add a slightly transparent shaded region showing the "buffer" time.
This approach has one caveat: buffer times may overlap appointments rather than pushing them onto new lines. this might be desirable though.
In the end, the buffer data is being treated more like helper text so I think it's the right solution.
Thank you!
Related
I'm using ArcRotateCamera, when I click on mesh, I have to focus camera on
var camera = new BABYLON.ArcRotateCamera("Camera", -Math.PI / 2, Math.PI / 2, 300, BABYLON.Vector3.Zero(), scene);
camera.setTarget(BABYLON.Vector3.Zero());
// on mesh click, focus in
var i = 2;
var pickInfo = scene.pick(scene.pointerX, scene.pointerY);
if (pickInfo.hit) {
pickInfo.pickedMesh.actionManager = new BABYLON.ActionManager(scene);
pickInfo.pickedMesh.actionManager.registerAction(
new BABYLON.ExecuteCodeAction(BABYLON.ActionManager.OnPickTrigger,
function (event) {
camera.position = (new BABYLON.Vector3(pickInfo.pickedPoint.x, pickInfo.pickedPoint.y, camera.position.z + i));
i += 2;
})
);
}
this code changes mesh's z position but don't makes it in the center of screen
There are a few things that can be changed in your code.
1st - what you are doing is executing a code action after a click, instead of simply running the code in the callback after a pick has occurred. You are registering a pick action (technically user click) on right on the first frame, but only if the mouse was found in the right location at the right moment. My guess is that it didn't work every time (unless you scene is covered with meshes :-) )
2nd - you are changing the camera's position, instead of change the position to which it is looking. Changing the camera's position won't result in what you want (to see the selected mesh), it will move the camera to a new position while still focusing on the old position.
There are a few ways to solve this. The first is this:
scene.onPointerDown = function(evt, pickInfo) {
if(pickInfo.hit) {
camera.focusOn([pickInfo.pickedMesh], true);
}
}
The ArcRotate camera provides focusOn function that focuses on a group of meshes, while fixing the orientation of the camera. this is very helpful. You can see a demo here:
https://playground.babylonjs.com/#A1210C#51
Another solution would be to use the setTarget function:
https://playground.babylonjs.com/#A1210C#52
Which works a bit differently (notice the orientation change of the camera).
Another thing - use the pointer events integrated in Babylon, as they are saving you the extra call for a scene pick. pointer down is executed with the pickinfo integrated in the function, so you can get the picking info of the current pointer down / up / move each frame.
**** EDIT ****
After a new comment - since you want to animate the values, all you need to do is store the current values, calculate the new ones, and animate the values using the internal animation system (documentation here - https://doc.babylonjs.com/babylon101/animations#basic-animation) . There are many ways to achieve this, I took an old function and modernized it :-)
Here is the demo - https://playground.babylonjs.com/#A1210C#53
enter image description hereWhat if we could simulate 6dof control on the Oculus Go controller? Imagine that we turn the controller 3d model into a hand, it still just rotates, but imagine that we use the touchpad to move the hand foward, left, right, or backwards in space, the touch pad gives you movement along a z and x axis in space, but the accelerometer/gyro gives you a y and x axis. so the accelerometer/gyro serves as the arm, and the touch pad serves as the hand/wrist, a hand that can move forward and back and only twist left and right, and grip with the trigger, the hand can't tilt up or down but the arm can make up for that. So how do I build this?
There is https://www.npmjs.com/package/aframe-thumb-controls-component that provides events for pressing thumbpad in directions (e.g., thumbupstart, thumbleftend).
Write a component that listens to those events, sets a property (e.g., this.buttons.left = true, then the tick handler needs to update the this.el.object3D.position based on which buttons are held down.
Also need to take into consideration the direction the camera is facing. https://github.com/aframevr/aframe/blob/master/src/components/wasd-controls.js is a good starting point is it is similar, where it listens to key downs and translates position. Just need to modify to use thumb-controls instead.
More hints:
<script src="https://unpkg.com/aframe-thumb-controls-component#1.1.0/dist/aframe-thumb-controls-component.min.js">
AFRAME.registerComponent('thumb-movement-controls', {
init: function () {
this.buttons = {
left: false, right: false, up: false, down: false
};
this.el.addEventListener('thumbleftstart', () => {
this.buttons.left = true;
});
this.el.addEventListener('thumbleftend', () => {
this.buttons.left = false;
});
},
tick: function () {
// Really simplified movement. Does not take into account camera heading or velocity / time, but wasd-controls shows how.
if (this.buttons.left) {
this.el.position.x -= 0.001;
}
}
});
<a-entity daydream-controls thumb-controls thumb-movement-controls></a-entity>
I am implementing the timeline view of Full Calendar in my project, and although it works and looks great, the only issue I have is that in timeline Month view, the event bars do not wrap so half the text is cut off, especially so when the event only lasts a couple of days.
In Week and Day view, the text wraps fine - it's just in Month view. Is there any way to allow it to wrap the text? In certain cases there are notes added to the booking so they are pretty much unreadable in month view.
I'm using this code to add the description:
eventRender: function(event, element) {
element.find(".fc-event-title").remove();
element.find(".fc-event-time").remove();
if(event.desc) {
var new_description =
'<br/><div class="fc-title">' + event.desc + '</div>'
;
element.append(new_description);
}
}
within my calendar params.
Here is a picture of what the entry looks like in timeline Month view:
And here is what it looks like in Day view (what I'd like it to look like):
If anyone can help with this I'd be grateful.
Just encountered the same problem, and this works for me...
.fc-event-time, .fc-event-title {
padding: 0 1px;
white-space: normal;
}
For instance, the longer someone is say, holding the mouse button or using an arrow key, change the image differently. Say a walking animation. When the user holds for say, the right arrow key, the walking animation appears. But there are multiple images in the sprite that you must use over a little time.
If it's a little vague, I can't help it. It's hard to explain.
Thanks in advance.
This is not too difficult to achieve. First apply a listener on the arrow key...
jQuery example.
$("document").ready(function() {
$(document).on('keydown', function(e) {
switch (e.keyCode) {
case 13:
// Perform some action when enter is placed
return;
case 37:
// animate left
animate.dir = 'left';
animate.moving = true;
animate.anim();
break;
case 38:
// animate up
break;
case 39:
// animate right
animate.dir = 'right';
animate.moving = true;
animate.anim();
break;
case 40:
// animate down
break;
}
}).on('keyup', function(){
animate.reset();
});
});
var animate = {
moving:false,
speed: 100,
dir: 'right',
frame_width: 100,
cur_position: 0,
queue: null,
anim: function(){
if(this.moving)
{
if(dir == 'right')
this.cur_position -= this.frame_width;
else
this.cur_position += this.frame_width;
$('#guy').css({backgroundPosition: this.cur_position + 'px 0' });
this.queue = setTimeout(function(){
this.anim();
}, this.speed);
}
},
reset: function(){
this.moving = false;
clearTimeout(animate.queue);
this.cur_position = 0;
$('#guy').css({backgroundPosition: '0 0' });
}
};
html:
<div id="guy"></div>
css:
#guy{
width:100px;
height:100px;
background: url(/image.png);
background-position:0 0;
}
I can't promise anything with this untested code but the general idea is correct. I've handled tons of user interaction based sprite animations.
The thing to remember is to have your animation call itself recursively while animate.moving == true. then on keyup you clear that timeout. With that basic thing in mind you can control the actions of animate.anim() however you choose. In this case I simply remove or add 100 pixels to the x-offset in background-position. That assumes your sprite is a horizontal image with each frame being 100 x 100 pixels.
IN ADDITION this code does NOT consider when the image should loop. So you will have to calculate this based on your image dimensions and the loop for each particular animation. If you get my example working, it should be trivial to apply the loop listener when needed. Simply post a question to this answer if you get that far and don't know what to do. I would write it here but really, you could write volumes on animation handling and I'd rather do it on demand than on speculation.
You can view source of one of my test domains animation fx on rollover and out:
http://www.wrightonwrong.com
You could always use an animated gif and then just make a sprite file and use it as usual.
How do you display a half-day event in the month view? For instance, I have an event that is 12 hours long. I would like the date cell for that event to only show a half bar. Is that possible? If so, how do you implement this?
So the events are positioned "absolute", this is a tricky one .....
Use of the eventAfterRender callback like this :
, eventAfterRender: function(event, element, view) {
/**
* get the width of first day slot in calendar table
* next to event container div
*/
var containerWidth = jQuery(element).offsetParent()
.siblings("table").find(".fc-day-content").width();
// half a day
var elementWidth = parseInt(containerWidth / 2);
// set width of element
jQuery(element).css('width', elementWidth + "px");
}
Surely can be improved :-)
A little late to the party, but I've just managed to implement this in a way that works great, and works when the page is resized too.
eventAfterRender doesnt seem to work for me, but eventRender will do the same thing:
eventRender: function (event, element) {
// Get the page width, then
// subtract the margins around the side. I'm assuming a full
// size calendar with a margin of 15px on each side here.
var width = getWidth()-30;
width = width / 14; (7 days = 14 half days)
jQuery(event.el).css('margin-left', width + "px");
}
You then need to reload the events when the browser window is resized so that they remain in the middle, otherwise they will drift.
window.addEventListener('resize', function () {
calendar.refetchEvents();
});
Note: for getting the browser width I'm using this function to ensure it works across different browsers:
function getWidth() {
return Math.max(
document.body.scrollWidth,
document.documentElement.scrollWidth,
document.body.offsetWidth,
document.documentElement.offsetWidth,
document.documentElement.clientWidth
);
}