help needed for making a calendar like MS Outlook? - layout

i am doing work on an app like MS Outlook Calender where user can put events etc.
i am having problem with event object layout according to size etc. as user can drag and re size the event object in MS outlook calender and the size of event objects sets automatically.
i need the algorithm for doing so i have write my own but there are several problems help needed.
this screen shot will show the event object arrangement that is dynamic.

here is the ans
you can go for rectangle packing algorithm but keep in mind the events should be sorted w.r.t time and date and only horizontal packing will work for you
here is the rectangle packing algo

Since you're using Flex, this isn't a direct answer to your question, but it will hopefully set you down the right path.
Try taking a look at how FullCalendar's week and day views implement this. FullCalendar is a jQuery plugin that renders a calendar which does exactly what you're looking for.
You'll have to extract the rendering logic from FullCalendar and translate it to your project in Flex. I know JavaScript and ActionScript are very similar, but I've never used Flex — sorry I can't be more help in that area.
FullCalendar's repo is here. Specifically, it looks like AgendaView.js is the most interesting file for you to look at.

I think you are asking about a general object layout algorithm, right?
I am quite sure that this is a NP-complete problem: Arrange a set if intervals, each defined by a start and end as few columns as possible.
Being NP-complete means, that your best shot is probably trying out all possible arrangements:
find clusters in your objects -- the groups where you have something to do, where intervals do overlap.
for each cluster do
let n be the number of objects in the cluster
if n is too high (like 10 or 15), stop and just draw overlapping objects
generate all possible orderings of the objects in the cluster (for n objects, these are n! possible combinations, i.e. 6 objects, 120 possible orderings)
for each ordering lay out the objects in a trivial manner: loop through the elements and place them in an existing column if it fits there, start a new column if you need one.
keep the layout with the least columns

Here is how I did it:
Events are packet into columns variable by day (or some other rule)
Events in one column are further separated into columns, as long as there is a continuous intersection on the Y-axis.
Events are assigned their X-axis value (0 to 1) and their X-size (0 to 1)
Events are recursively expanded, until the last of each intersectioned group (by Y and X axis) hits the column barrier or another event, that has finished expanding.
Essentially it is a brute force, but works fairly quickly, since there are not many events that need further expanding beyond step 3.
var physics = [];
var step = 0.01;
var PackEvents = function(columns){
var n = columns.length;
for (var i = 0; i < n; i++) {
var col = columns[ i ];
for (var j = 0; j < col.length; j++)
{
var bubble = col[j];
bubble.w = 1/n;
bubble.x = i*bubble.w;
}
}
};
var collidesWith = function(a,b){
return b.y < a.y+a.h && b.y+b.h > a.y;
};
var intersects = function(a,b){
return b.x < a.x+a.w && b.x+b.w > a.x &&
b.y < a.y+a.h && b.y+b.h > a.y;
};
var getIntersections = function(box){
var i = [];
Ext.each(physics,function(b){
if(intersects(box,b) && b.x > box.x)
i.push(b);
});
return i;
};
var expand = function(box,off,exp){
var newBox = {
x:box.x,
y:box.y,
w:box.w,
h:box.h,
collision:box.collision,
rec:box.rec
};
newBox.x += off;
newBox.w += exp;
var i = getIntersections(newBox);
var collision = newBox.x + newBox.w > 1;
Ext.each(i,function(n){
collision = collision || expand(n,off+step,step) || n.collision;
});
if(!collision){
box.x = newBox.x;
box.w = newBox.w;
box.rec.x = box.x;
box.rec.w = box.w;
}else{
box.collision = true;
}
return collision;
};
Ext.each(columns,function(column){
var lastEventEnding = null;
var columns = [];
physics = [];
Ext.each(column,function(a){
if (lastEventEnding !== null && a.y >= lastEventEnding) {
PackEvents(columns);
columns = [];
lastEventEnding = null;
}
var placed = false;
for (var i = 0; i < columns.length; i++) {
var col = columns[ i ];
if (!collidesWith( col[col.length-1], a ) ) {
col.push(a);
placed = true;
break;
}
}
if (!placed) {
columns.push([a]);
}
if (lastEventEnding === null || a.y+a.h > lastEventEnding) {
lastEventEnding = a.y+a.h;
}
});
if (columns.length > 0) {
PackEvents(columns);
}
Ext.each(column,function(a){
a.box = {
x:a.x,
y:a.y,
w:a.w,
h:a.h,
collision:false,
rec:a
};
physics.push(a.box);
});
while(true){
var box = null;
for(i = 0; i < physics.length; i++){
if(!physics[i].collision){
box = physics[i];
break;
}
}
if(box === null)
break;
expand(box,0,step);
}
});
Result: http://imageshack.com/a/img913/9525/NbIqWK.jpg

Related

Prevent nested lists in text-editor (froala)

I need to prevent/disable nested lists in text editor implemented in Angular. So far i wrote a hack that undos a nested list when created by the user. But if the user creates a normal list and presses the tab-key the list is shown as nested for a few milliseconds until my hack sets in back to a normal list. I need something like event.preventDefault() or stopPropagation() on tab-event keydown but unfortunately that event is not tracked for some reason. Also the froala settings with tabSpaces: falseis not showing any difference when it comes to nested list...in summary i want is: if the user creates a list and presses the tab-key that nothing happens, not even for a millisecond. Has anyone an idea about that?
Froala’s support told us, there’s no built-in way to suppress nested list creation. They result from TAB key getting hit with the caret on a list item. However we found a way to get around this using MutationObserver
Basically we move the now nested list item to his former sibling and remove the newly created list. Finally we take care of the caret position.
var observer = new MutationObserver(mutationObserverCallback);
observer.observe(editorNode, {
childList: true,
subtree: true
});
var mutationObserverCallback = function (mutationList) {
var setCaret = function (ele) {
if (ele.nextSibling) {
ele = ele.nextSibling;
}
var range = document.createRange();
var sel = window.getSelection();
range.setStart(ele, 0);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
};
var handleAddedListNode = function (listNode) {
if (! listNode.parentNode) {
return;
}
var parentListItem = listNode.parentNode.closest('li');
if (!parentListItem) {
return;
}
var idx = listNode.children.length - 1;
while (idx >= 0) {
var childNode = listNode.children[idx];
if (parentListItem.nextSibling) {
parentListItem.parentNode.insertBefore(childNode, parentListItem.nextSibling);
} else {
parentListItem.parentNode.appendChild(childNode);
}
--idx;
}
setCaret(parentListItem);
listNode.parentNode.removeChild(listNode);
};
mutationList.forEach(function (mutation) {
var addedNodes = mutation.addedNodes;
if (!addedNodes.length) {
return;
}
for (var i = 0; i < addedNodes.length; i++) {
var currentNode = addedNodes[i];
switch (currentNode.nodeName.toLowerCase()) {
case 'ol':
case 'ul':
handleAddedListNode(currentNode);
break;
// more optimizations
}
}
})
};

Is it normal to solve a TSP with GA(Genetic Algorithyms) implementation takes much time?

I am working on GA for a project. I am trying to solve Travelling Salesman Problem using GA. I used array[] to store data, I think Arrays are much faster than List. But for any reason it takes too much time. e.g. With MaxPopulation = 100000, StartPopulation=1000 the program lasts to complete about 1 min. I want to know if this is a problem. If it is, how can I fix this?
A code part from my implementation:
public void StartAsync()
{
Task.Run(() =>
{
CreatePopulation();
currentPopSize = startPopNumber;
while (currentPopSize < maxPopNumber)
{
Tour[] elits = ElitChromosoms();
for (int i = 0; i < maxCrossingOver; i++)
{
if (currentPopSize >= maxPopNumber)
break;
int x = rnd.Next(elits.Length - 1);
int y = rnd.Next(elits.Length - 1);
Tour parent1 = elits[x];
Tour parent2 = elits[y];
Tour child = CrossingOver(parent1, parent2);
int mut = rnd.Next(100);
if (mutPosibility >= mut)
{
child = Mutation(child);
}
population[currentPopSize] = child;
currentPopSize++;
}
progress = currentPopSize * 100 / population.Length;
this.Progress = progress;
GC.Collect();
}
if (GACompleted != null)
GACompleted(this, EventArgs.Empty);
});
}
In here "elits" are the chromosoms that have greater fit value than the average fit value of the population.
Scientific papers suggest smaller population. Maybe you should follow what is written by the other authors. Having big population does not give you any advantage.
TSP can be solved by GA, but maybe it is not the most efficient approach to attack this problem. Look at this visual representation of TSP-GA: http://www.obitko.com/tutorials/genetic-algorithms/tsp-example.php
Ok. I have just found a solution. Instead of using an array with size of maxPopulation, change new generations with the old and bad one who has bad fitness. Now, I am working with a less sized array, which has length of 10000. The length was 1,000.000 before and it was taking too much time. Now, in every iteration, select best 1000 chromosomes and create new chromosomes using these as parent and replace to old and bad ones. This works perfect.
Code sample:
public void StartAsync()
{
CreatePopulation(); //Creates chromosoms for starting
currentProducedPopSize = popNumber; //produced chromosom number, starts with the length of the starting population
while (currentProducedPopSize < maxPopNumber && !stopped)
{
Tour[] elits = ElitChromosoms();//Gets best 1000 chromosoms
Array.Reverse(population);//Orders by descending
this.Best = elits[0];
//Create new chromosom as many as the number of bad chromosoms
for (int i = 0; i < population.Length - elits.Length; i++)
{
if (currentProducedPopSize >= maxPopNumber || stopped)
break;
int x = rnd.Next(elits.Length - 1);
int y = rnd.Next(elits.Length - 1);
Tour parent1 = elits[x];
Tour parent2 = elits[y];
Tour child = CrossingOver(parent1, parent2);
int mut = rnd.Next(100);
if (mutPosibility <= mut)
{
child = Mutation(child);
}
population[i] = child;//Replace new chromosoms
currentProducedPopSize++;//Increase produced chromosom number
}
progress = currentProducedPopSize * 100 / maxPopNumber;
this.Progress = progress;
GC.Collect();
}
stopped = false;
this.Best = population[population.Length - 1];
if (GACompleted != null)
GACompleted(this, EventArgs.Empty);
}
Tour[] ElitChromosoms()
{
Array.Sort(population);
Tour[] elits = new Tour[popNumber / 10];
Array.Copy(population, elits, elits.Length);
return elits;
}

cloning/copying a dojo data store

Hi can some one please tell me how to copy one data store to another in dojo. I tried it in following way but it doesn't work. Here I'm try to copy data from jsonStore to newGridStore.
jsonStore.fetch({query:{} , onComplete: onComplete});
var onComplete = function (items, request) {
newGridStore = null;
newGridStore = new dojo.data.ItemFileWriteStore({
data : {}
});
if (items && items.length > 0) {
var i;
for (i = 0; i < items.length; i++) {
var item = items[i];
var attributes = jsonStore.getAttributes(item);
if (attributes && attributes.length > 0) {
var j;
for (j = 0; j < attributes.length; j++) {
var newItem = {};
var values = jsonStore.getValues(item, attributes[j]);
if (values) {
if (values.length > 1) {
// Create a copy.
newItem[attributes[j]] = values.slice(0, values.length);
} else {
newItem[attributes[j]] = values[0];
}
}
}
newGridStore.newItem(newItem);
}
}
}
}
Based on the comments asked above. You are trying to copy values to a new Store for the single reason to be able to detect which values have changes and then save them individually, without having to send the entire store.
This approach is totally wrong.
Dojo has isDirty() and offers you the ability to revert() a store back to it's original values. It knows which values have changed and you don't need to do this.
Take a look at the bog standard IFWS here: http://docs.dojocampus.org/dojo/data/ItemFileWriteStore
Make sure you read everything from here: http://docs.dojocampus.org/dojo/data/ItemFileWriteStore#id8
What you want to do is create your own _saveCustom method which you will override your store with, and then when you save, you will be able to see which values have changed.
Click on the demo at the very bottom of the page. It shows you EXACTLY how do to it using _saveCustom

Drag/Move Multiple Selected Features - OpenLayers

I know that I can easily allow a user to select multiple Features/Geometries in OpenLayers but I then want enable the user to easily drag/move all of the selected features at the same time.
With the ModifyFeature control it only moves one feature at a time ... is there a way to easily extend this control (or whatever works) to move all of the selected features on that layer?
Okay, skip the ModifyFeature control and just hook into the SelectFeature control to keep track of the selected features and then use the DragControl to manipulate the selected points at the same time.
Example of the control instantiation:
var drag = new OpenLayers.Control.DragFeature(vectors, {
onStart: startDrag,
onDrag: doDrag,
onComplete: endDrag
});
var select = new OpenLayers.Control.SelectFeature(vectors, {
box: true,
multiple: true,
onSelect: addSelected,
onUnselect: clearSelected
});
Example of the event handling functions:
/* Keep track of the selected features */
function addSelected(feature) {
selectedFeatures.push(feature);
}
/* Clear the list of selected features */
function clearSelected(feature) {
selectedFeatures = [];
}
/* Feature starting to move */
function startDrag(feature, pixel) {
lastPixel = pixel;
}
/* Feature moving */
function doDrag(feature, pixel) {
for (f in selectedFeatures) {
if (feature != selectedFeatures[f]) {
var res = map.getResolution();
selectedFeatures[f].geometry.move(res * (pixel.x - lastPixel.x), res * (lastPixel.y - pixel.y));
vectors.drawFeature(selectedFeatures[f]);
}
}
lastPixel = pixel;
}
/* Featrue stopped moving */
function endDrag(feature, pixel) {
for (f in selectedFeatures) {
f.state = OpenLayers.State.UPDATE;
}
}
Hmm...
I tried the code above, and couldn't make it work. Two issues:
1) To move each feature, you need to use the original position of that feature, and add the "drag vector" from whatever feature the DragControl is moving around by itself (i.e. the feature-parameter to doDrag).
2) Since DragFeatures own code sets lastPixel=pixel before calling onDrag, the line calling move() will move the feature to (0,0).
My code looks something like this:
var lastPixels;
function startDrag(feature, pixel) {
// save hash with selected features start position
lastPixels = [];
for( var f=0; f<wfs.selectedFeatures.length; f++){
lastPixels.push({ fid: layer.selectedFeatures[f].fid,
lastPixel: map.getPixelFromLonLat( layer.selectedFeatures[f].geometry.getBounds().getCenterLonLat() )
});
}
}
function doDrag(feature, pixel) {
/* because DragFeatures own handler overwrites dragSelected.lastPixel with pixel before this is called, calculate drag vector from movement of "feature" */
var g = 0;
while( lastPixels[g].fid != feature.fid ){ g++; }
var lastPixel = lastPixels[g].lastPixel;
var currentCenter = map.getPixelFromLonLat( feature.geometry.getBounds().getCenterLonLat() );
var dragVector = { dx: currentCenter.x - lastPixel.x, dy: lastPixel.y - currentCenter.y };
for( var f=0; f<layer.selectedFeatures.length; f++){
if (feature != layer.selectedFeatures[f]) {
// get lastpixel of this feature
lastPixel = null;
var h = 0;
while( lastPixels[h].fid != layer.selectedFeatures[f].fid ){ h++; }
lastPixel = lastPixels[h].lastPixel;
var newPixel = new OpenLayers.Pixel( lastPixel.x + dragVector.dx, lastPixel.y - dragVector.dy );
// move() moves polygon feature so that centre is at location given as parameter
layer.selectedFeatures[f].move(newPixel);
}
}
}
I had a similar problem and solved it by overriding DragFeature's moveFeature function and putting this.lastPixel = pixel inside the for loop that applies the move to all features within my layer vector. Until I moved this.lastPixel = pixel inside the loop, all features except the one being dragged got crazily distorted.
`OpenLayers.Control.DragFeature.prototype.moveFeature = function (pixel) {
var res = this.map.getResolution();
for (var i = 0; i < vector.features.length; i++) {
var feature = vector.features[i];
feature .geometry.move(res * (pixel.x - this.lastPixel.x),
res * (this.lastPixel.y - pixel.y));
this.layer.drawFeature(feature );
this.lastPixel = pixel;
}
this.onDrag(this.feature, pixel);
};
`

Help on Removal of Dynamically Created sprites

import flash.display.Sprite;
import flash.net.URLLoader;
var index:int = 0;
var constY = 291;
var constW = 2;
var constH = 40;
hydrogenBtn.label = "Hydrogen";
heliumBtn.label = "Helium";
lithiumBtn.label = "Lithium";
hydrogenBtn.addEventListener (MouseEvent.CLICK, loadHydrogen);
heliumBtn.addEventListener (MouseEvent.CLICK, loadHelium);
lithiumBtn.addEventListener (MouseEvent.CLICK, loadLithium);
var myTextLoader:URLLoader = new URLLoader();
myTextLoader.addEventListener(Event.COMPLETE, onLoaded);
function loadHydrogen (event:Event):void {
myTextLoader.load(new URLRequest("hydrogen.txt"));
}
function loadHelium (event:Event):void {
myTextLoader.load(new URLRequest("helium.txt"));
}
function loadLithium (event:Event):void {
myTextLoader.load(new URLRequest("lithium.txt"));
}
var DataSet:Array = new Array();
var valueRead1:String;
var valueRead2:String;
function onLoaded(event:Event):void {
var rawData:String = event.target.data;
for(var i:int = 0; i<rawData.length; i++){
var commaIndex = rawData.search(",");
valueRead1 = rawData.substr(0,commaIndex);
rawData = rawData.substr(commaIndex+1, rawData.length+1);
DataSet.push(valueRead1);
commaIndex = rawData.search(",");
if(commaIndex == -1) {commaIndex = rawData.length+1;}
valueRead2 = rawData.substr(0,commaIndex);
rawData = rawData.substr(commaIndex+1, rawData.length+1);
DataSet.push(valueRead2);
}
generateMask_Emission(DataSet);
}
function generateMask_Emission(dataArray:Array):void{
var spriteName:String = "Mask"+index;
trace(spriteName);
this[spriteName] = new Sprite();
for (var i:int=0; i<dataArray.length; i+=2){
this[spriteName].graphics.beginFill(0x000000, dataArray[i+1]);
this[spriteName].graphics.drawRect(dataArray[i],constY,constW, constH);
this[spriteName].graphics.endFill();
}
addChild(this[spriteName]);
index++;
}
Hi, I am relatively new to flash and action script as well and I am having a problem getting the sprite to be removed after another is called. I am making emission spectrum's of 3 elements by dynamically generating the mask over a picture on the stage. Everything works perfectly fine with the code I have right now except the sprites stack on top of each other and I end up with bold lines all over my picture instead of a new set of lines each time i press a button.
I have tried using try/catch to remove the sprites and I have also rearranged the entire code from what is seen here to make 3 seperate entities (hoping I could remove them if they were seperate variables) instead of 2 functions that handle the whole process. I have tried everything to the extent of my knowledge (which is pretty minimal # this point) any suggestions?
Thanks ahead of time!
My AS3 knowledge is rather rudimentary right now but I think two things may help you.
You could use removeChild before recreating the Sprite. Alternatively, just reuse the Sprite.
Try to add this[spriteName].graphics.clear(); to reset the sprite and start redrawing.
function generateMask_Emission (dataArray : Array) : void {
var spriteName:String = "Mask"+index;
trace(spriteName);
// Don't recreate if sprite object already created
if (this[spriteName] == null)
{
this[spriteName] = new Sprite();
// Only need to add sprite to display object once
addChild(this[spriteName]);
}
for (var i:int= 0; i < dataArray.length; i+=2)
{
this[spriteName].graphics.clear();
this[spriteName].graphics.beginFill(0x000000, dataArray[i+1]);
this[spriteName].graphics.drawRect(dataArray[i],constY,constW, constH);
this[spriteName].graphics.endFill();
}
index++;
}
Just in case anyone was curious or having a similar problem. Extremely simple fix but here is what I did.
Also should mention that I don't think that the graphics.clear function actually fixed the problem (though I didn't have the sprite being cleared properly before), but I believe the problem lies in the beginning of the onloaded function where 3 of those variables used to be outside of the function.
import flash.display.Sprite;
import flash.net.URLLoader;
import flash.events.Event;
var constY = 291; //this value represets the Y value of the bottom of the background spectrum image
var constW = 2; //this value represents the width of every emission line
var constH = 40; //this value represents the height of every emission line
//Create Button Labels
hydrogenBtn.label = "Hydrogen";
heliumBtn.label = "Helium";
lithiumBtn.label = "Lithium";
//These listen for the buttons to be clicked to begin loading in the data
hydrogenBtn.addEventListener (MouseEvent.CLICK, loadHydrogen);
heliumBtn.addEventListener (MouseEvent.CLICK, loadHelium);
lithiumBtn.addEventListener (MouseEvent.CLICK, loadLithium);
var myTextLoader:URLLoader = new URLLoader();//the object to load in data from external files
myTextLoader.addEventListener(Event.COMPLETE, onLoaded);//triggers the function when the file is loaded
var Mask:Sprite = new Sprite(); //This sprite will hold the information for the spectrum to be put on stage
function loadHydrogen (event:Event):void {
myTextLoader.load(new URLRequest("hydrogen.txt"));//starts loading Hydrogen emisson data
}
function loadHelium (event:Event):void {
myTextLoader.load(new URLRequest("helium.txt"));//starts loading Helium emission data
}
function loadLithium (event:Event):void {
myTextLoader.load(new URLRequest("lithium.txt"));//starts loading Lithium emission data
}
function onLoaded(event:Event):void {//the function that handles the data from the external file
var rawData:String = event.target.data; //create a new string and load in the data from the file
var DataSet:Array = new Array();//the array to load values in to
var valueRead1:String; //subset of array elements (n)
var valueRead2:String; //subset of array elements (n+1)
for(var i:int = 0; i<rawData.length; i++){ //loop through the string and cut up the data # commas
var commaIndex = rawData.search(",");
valueRead1 = rawData.substr(0,commaIndex);
rawData = rawData.substr(commaIndex+1, rawData.length+1);
DataSet.push(valueRead1);
commaIndex = rawData.search(",");
if(commaIndex == -1) {commaIndex = rawData.length+1;}
valueRead2 = rawData.substr(0,commaIndex);
rawData = rawData.substr(commaIndex+1, rawData.length+1);
DataSet.push(valueRead2);
}
generateMask_Emission(DataSet);//call the generateMaskEmission function on new data to fill emission lines
}
//This function loops through an array, setting alternating values as locations and alphas
function generateMask_Emission(dataArray:Array):void{
Mask.graphics.clear(); //Clears the Mask sprite for the next set of values
addChild(Mask); //Adds the blank sprite in order to clear the stage of old sprites
//This loop actually draws out how the sprite should look before it is added
for (var i:int=0; i<dataArray.length; i+=2){
Mask.graphics.beginFill(0x000000, dataArray[i+1]);
Mask.graphics.drawRect(dataArray[i],constY,constW, constH);
Mask.graphics.endFill();
}
addChild(Mask);// actually adds the mask we have created to the stage
}

Resources