/// <summary> /// Loads all mutual friends of all friends and saves them into a graph /// </summary> public void LoadConnections(FriendList fl, BackgroundWorker worker = null) { data = new FriendGraph(); friends = new Dictionary <string, Friend>(); // creates id->friend addresser foreach (Friend f in fl) { friends.Add(f.id, f); data.Add(f, new List <Friend>()); } // downloades mutual friends of every friend in the list int i = 0; foreach (KeyValuePair <string, Friend> pair in friends) { if (worker != null && worker.CancellationPending) { throw new InterruptedException(); } FriendList mutualFriends = GraphAPI.GetData <FriendList>(pair.Key + "/mutualfriends"); foreach (Friend f in mutualFriends) { if (!data[pair.Value].Contains(f)) { data[pair.Value].Add(f); } } // reporting progress if (worker != null) { worker.ReportProgress((++i * 100) / friends.Count, i); } } }
/// <summary> /// Loads saved connection out of a file /// </summary> public void LoadConnections(string filename, BackgroundWorker worker = null) { Dictionary <string, List <Friend> > parsedData; data = new FriendGraph(); friends = new Addresser(); // loading raw data about friends to an object in an undesired format using (FileStream fs = File.Open(filename, FileMode.Open)) using (StreamReader sr = new StreamReader(fs)) using (JsonTextReader jr = new JsonTextReader(sr)) { JsonSerializer serializer = new JsonSerializer(); parsedData = serializer.Deserialize <Dictionary <string, List <Friend> > >(jr); } // reporting progress if (worker != null) { worker.ReportProgress(15); } int i = 0; // find all distinct friends and create id->friend addresser // friends with no mutual friends with us will get lost (but what would they do inside the graph anyway) foreach (KeyValuePair <string, List <Friend> > pair in parsedData) { if (worker != null && worker.CancellationPending) { throw new InterruptedException(); } foreach (Friend f in pair.Value) { if (!friends.ContainsKey(f.id)) { friends.Add(f.id, f); data.Add(f, new List <Friend>()); } } // reporting progress if (worker != null) { worker.ReportProgress(15 + (++i * 70) / parsedData.Count); } } i = 0; // create the real graph out of the list of connections (connect our addresser) foreach (KeyValuePair <string, List <Friend> > pair in parsedData) { foreach (Friend f in pair.Value) { data[friends[pair.Key]].Add(friends[f.id]); // we add inside friends[f.id] not f so we unify the pointers } // (and actually toss away a lot of redundant data) // reporting progress if (worker != null) { worker.ReportProgress(85 + (++i * 15) / parsedData.Count); } } }
/// <summary> /// Draws a graph of friends into a Bitmap /// </summary> /// <param name="graph">Friend connection graf</param> /// <param name="srcDir">Where to take user profile picture thumbnails from</param> /// <param name="settings">Settings - when left blank, default settings are used</param> /// <param name="worker">To report the progress</param> /// <returns>Bitmap with the graph</returns> private static Bitmap DrawGraph(FriendGraph graph, string imageDir, BackgroundWorker worker = null) { Bitmap bmp = new Bitmap(GraphSettings.ImageWidth, GraphSettings.ImageHeight); Graphics g = Graphics.FromImage(bmp); g.Clear(Color.White); g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias; // if we have the autosize option on, we find the maximum number of friends int maxFriends = 0; // we draw lines connecting friends int i = 0; List <Friend> done = new List <Friend>(); // so we dont draw lines both ways foreach (KeyValuePair <Friend, List <Friend> > pair in graph) { if (worker != null && worker.CancellationPending) { throw new InterruptedException(); } Pen pen = new Pen(Color.FromArgb(64, 0, 0, 0), 1); foreach (Friend f in pair.Value) { if (!done.Contains(f)) { g.DrawLine(pen, pair.Key.coordinates, f.coordinates); } } if (pair.Value.Count > maxFriends) { maxFriends = pair.Value.Count; } pen.Dispose(); done.Add(pair.Key); if (worker != null) { worker.ReportProgress(Math.Min(99, ++i * 50 / graph.Count)); } } int photoSize = GraphSettings.PhotoSize; // if we have the autosize option on, we would like bigger pictures be on top of smaller // we sort them by their friend count asc if (GraphSettings.AutoSize) { done.Sort((x, y) => { if (graph[x].Count < graph[y].Count) { return(-1); } else if (graph[y].Count < graph[x].Count) { return(1); } return(0); }); } // we draw profile photos inside foreach (Friend f in done) { if (worker != null && worker.CancellationPending) { throw new InterruptedException(); } Image photo = Image.FromFile(imageDir + "/photos/" + f.id + ".jpg"); if (GraphSettings.AutoSize) { photoSize = (int)(15 + 35 * ((float)graph[f].Count / (float)maxFriends)); } if (GraphSettings.PhotoShape == Shape.Circle) // we must crop circle out of the profile picture // we create brush { TextureBrush brush = new TextureBrush(photo, WrapMode.Clamp); // resize the brush brush.ScaleTransform(((float)photoSize) / 50f, ((float)photoSize) / 50f, MatrixOrder.Append); // we reset the brush starting position brush.TranslateTransform(f.coordinates.X - photoSize / 2, f.coordinates.Y - photoSize / 2, MatrixOrder.Append); // and fill a circle with it g.FillEllipse(brush, f.coordinates.X - photoSize / 2, f.coordinates.Y - photoSize / 2, photoSize, photoSize); brush.Dispose(); } else // square - just draw the image { g.DrawImage(photo, f.coordinates.X - photoSize / 2, f.coordinates.Y - photoSize / 2, photoSize, photoSize); } photo.Dispose(); if (worker != null) { worker.ReportProgress(Math.Min(99, ++i * 50 / graph.Count)); } } g.Dispose(); return(bmp); }