del.icio.usで最近ブックマークしたものを可視化してみる。 2008/05/11
2008/05/11

はじめに


ここ数日間やってたことのまとめです。
del.icio.usで最近ブックマークしたものを日付ごとで、表示します。その時に、ブックマークした記事をsimpleapiでサムネイル化したものを取得して、アイソメトリックな感じで表示します。

日付ごとでどれだけブックマークされた記事が多いかわかりやすくなったかな。

結果、こんな感じ。



実装


描画するまでは何となくできたのですが、これを並べ替えたり、操作するのってもう少し練らないと。
はじめから3Dを使うというアプローチのほうがよいのかな。

基本は四角のものをBufferedImageにして、つぎに、それをAffineTransformで、shearします。
それを重ねて描画します。その時に、描画する位置を、計算。下記のユーティリティメソッド使ってます。

package d;

import java.awt.Point;

public class IsometricUtils {

/**
* 中心位置から指定された角度の点を求めます。
* @param degree 角度
* @param cx 中心位置
* @param cy 中心位置
* @param R 距離
* @return
*/
static public Point point(double degree, int cx, int cy, int R) {
int x = (int) (cx + (R * Math.sin(Math.toRadians(degree))));
int y = (int) (cy + (R * Math.cos(Math.toRadians(degree))));
return new Point(x, y);
}

}


あと、del.icio.us apiの決まり事で、

Please wait AT LEAST ONE SECOND between queries, or you are likely to get automatically throttled. If you are releasing a library to access the API, you MUST do this.

クエリーの間隔をあけないといけないみたいなんだけど、ばこすかアクセスしてたせいなのかしらないけど、途中で、エラーがでて、壱時間ぐらいアクセスできなくなったので、注意すべし。

以下、とりあえず、コード。長いけど。
package d;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.AreaAveragingScaleFilter;
import java.awt.image.BufferedImage;
import java.awt.image.FilteredImageSource;
import java.awt.image.ImageFilter;
import java.awt.image.ImageProducer;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathExpressionException;

import org.apache.http.HttpException;
import org.xml.sax.SAXException;

import d.DeliciousUtils.Post;

public class Test {

public static void main(String[] args) throws Exception {
a();
}

static void a() throws IOException, HttpException, InterruptedException,
URISyntaxException, XPathExpressionException, SAXException,
ParserConfigurationException {

final List<BufferedImage> list1 = c("username", "password");

System.out.println(list1);
JFrame frame = new JFrame();
class P extends JPanel {

@Override
protected void paintChildren(Graphics g) {
Graphics2D g2d = (Graphics2D) g;

if (!(0 < list1.size()))
return;

Point P = new Point(10, 10);

Point p2 = new Point(P.x, list1.get(0).getHeight());
for (BufferedImage image : list1) {
// int yy = p2.y - image.getHeight();
g2d.drawImage(image, P.x, P.y, null);
P = IsometricUtils.point(60, P.x, P.y, 70);

}

}

}
P p = new P();
p.setBackground(Color.black);
frame.getContentPane().add(p);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 500);
frame.setVisible(true);

}

/**
* サイズの大きいイメージに大きさをあわせてイメージをつくりなおします。
*
* @param list
* @return
*/
static List<BufferedImage> d(List<BufferedImage> list) {
int w = 0;
int h = 0;
for (BufferedImage image : list) {
System.out.println(image);
w = w < image.getWidth() ? image.getWidth() : w;
h = h < image.getHeight() ? image.getHeight() : h;
}

List<BufferedImage> list2 = new ArrayList<BufferedImage>();
for (BufferedImage image : list) {
BufferedImage image2 = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB);
int x = w - image.getWidth();
int y = (h - image.getHeight());

image2.createGraphics().drawImage(image, x, 0, null);

System.out.println("x:" + x + " y:" + y);
list2.add(image2);
}

return list2;
}

/**
* おおまかなロジックの流れ<br>
* (1)デリシャアスから最近のブックマークをとってきます。<br>
* (2)日付順で記事を分けます<br>
* (3)simpleapiを使って画像を取得します。<br>
* (4)表示のために空のイメージを足したりする<br>
*
* @param username
* @param passowrd
* @return
* @throws IOException
* @throws HttpException
* @throws InterruptedException
* @throws URISyntaxException
* @throws XPathExpressionException
* @throws SAXException
* @throws ParserConfigurationException
*/
static List<BufferedImage> c(String username, String passowrd)
throws IOException, HttpException, InterruptedException,
URISyntaxException, XPathExpressionException, SAXException,
ParserConfigurationException {
String sxml = DeliciousUtils.recent(username, passowrd);
if (sxml == null)
return null;
// System.out.println(sxml);
List<Post> posts = DeliciousUtils.toPosts(sxml);
if (!(0 < posts.size()))
return null;
final List<BufferedImage> list = new ArrayList<BufferedImage>();
Map<Integer, List<Post>> map = new TreeMap<Integer, List<Post>>();

for (Post post : posts) {
Integer t = getTime_yyyyMMdd(post.time);
if (!map.containsKey(t)) {
List<Post> list2 = new ArrayList<Post>();
list2.add(post);
map.put(t, list2);
continue;
}

map.get(t).add(post);
}

// 揃えて表示させるための処理(よくない)
int max = 0;
Iterator<List<Post>> it = map.values().iterator();
while (it.hasNext()) {
List<d.DeliciousUtils.Post> list3 = (List<d.DeliciousUtils.Post>) it
.next();
max = (max < list3.size()) ? list3.size() : max;
}

System.out.println(map);
List<BufferedImage> list2 = new ArrayList<BufferedImage>();
Iterator<Integer> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
Integer key = iterator.next();
List<d.DeliciousUtils.Post> list3 = (List<d.DeliciousUtils.Post>) map
.get(key);
Iterator<DeliciousUtils.Post> iterator2 = list3.iterator();

List<BufferedImage> list4 = new ArrayList<BufferedImage>();
while (iterator2.hasNext()) {
DeliciousUtils.Post post = (DeliciousUtils.Post) iterator2
.next();
list4.add(simpleapi(post.href));
}
// 揃えて表示させるための処理(よくない)
for (int i = list4.size(); i < max; i++) {
// 空のイメージを追加
list4.add(0, new BufferedImage(50, 50,
BufferedImage.TYPE_INT_ARGB));
}

list4.add(imageDate("" + key));
// 日付単位のイメージ
list2.add(create1(list4));
}
// System.out.println(list2);
return list2;
}

/**
* Listで受け取ったイメージを一枚一枚づつshearして、並べて一枚のBufferedImageにします。
*
* @param list
* @return
*/
static BufferedImage create1(List<BufferedImage> list) {
final AffineTransform affineTransform = new AffineTransform();

affineTransform.shear(0, Math.toRadians(30));
affineTransform.scale(.82602, 1);
// affineTransform.scale(.3, .3);

final AffineTransformOp op = new AffineTransformOp(affineTransform,
AffineTransformOp.TYPE_BICUBIC);

final List<Image> list2 = new ArrayList<Image>();

final int W = 53;
final int H = 92;
for (BufferedImage image : list) {

image = op.filter(image, null);
ImageFilter filter = new AreaAveragingScaleFilter(W, H);
ImageProducer im = new FilteredImageSource(image.getSource(),
filter);
Image newImage = Toolkit.getDefaultToolkit().createImage(im);
list2.add(newImage);
}

int w = W + (list2.size() * 10);
int h = H + (list2.size() * 10);

BufferedImage b = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2D = (Graphics2D) b.getGraphics();
g2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

int x = w - W;
int y = 0;

// System.out.println(w + " " + h);
g2D.setBackground(Color.LIGHT_GRAY);

for (Image image : list2) {
Point point = IsometricUtils.point(-60, x, y, 10);
g2D.drawImage(image, point.x, point.y, null);
x = point.x;
y = point.y;
}
g2D.dispose();
return b;
}

/**
* simpleapiを使ってイメージを取得
*
* @param href
* @return
*/
static BufferedImage simpleapi(String href) {
try {
return ImageIO.read(new URL("http://img.simpleapi.net/small/"
+ href));
} catch (Exception e) {
System.out.println(e);
}
return null;
}

/**
* 比較しやすいように年月日を取得します。
*
* @param time
* @return
*/
public static int getTime_yyyyMMdd(String time) {

try {
Date date = new SimpleDateFormat("yyyy-MM-dd").parse(time);
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd");
return Integer.parseInt(format.format(date));
} catch (ParseException e) {
e.printStackTrace();
}
return 0;
}

/**
* 日付を書いたプレートをつくる。
* @param sdate
* @return
*/
static BufferedImage imageDate(String sdate) {
BufferedImage b = new BufferedImage(128, 128,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = b.createGraphics();
g2d.setColor(Color.LIGHT_GRAY);
g2d.fillRect(0, 95, 128, 48);
g2d.setColor(Color.ORANGE);
g2d.fillRect(4, 95, 120, 48);
g2d.setColor(Color.BLACK);
g2d.setFont(new Font("", Font.BOLD, 20));
g2d.drawString(sdate, 5, 120);
g2d.dispose();
return b;
}
}

: