import java.applet.Applet; import java.awt.*; /** * TLS風のステータス画面を表示するアプレット. */ public class ProfileChart extends Applet { /** * あなたの名前 */ String name; /** * パラメータ */ int param[]; /** * 画面上で選択中のパラメータ */ int param_selected = -1; /** * パラメータ一覧を描画する左上座標 */ Point paramtable_top; /** * パラメータ一覧描画時の縦方向の間隔 */ int paramtable_step; /** * 描画に使用するフォント */ Font font; /** * 円グラフの中心位置 */ Point pie_center; /** * 円グラフの半径 */ int pie_radius; /** * フォントの getAscend */ int font_ascend; /** * フォントの stringWidth */ int font_width; /** * オフスクリーン */ Image offimage; /** * オフグラフィックス */ Graphics offgraphics; /** * パラメータ名 */ static String param_name[] = { "勉強・・・・", "運動・・・・", "センス・・・", "性格・・・・", "態度・・・・" }; static String param_value[][] = { {"いまいち", "もうひとつ", "ふつう", "まあまあ", "ばっちり"}, {"運動オンチ", "もうひとつ", "ふつう", "結構いける", "抜群"}, {"ダサダサ", "ちょっとね", "一般的", "なかなか", "ばっちり"}, {"おとなしい", "おとなしめ", "ふつう", "けっこう活発", "すごく活発"}, {"不真面目", "不真面目気味", "ふつう", "まあ真面目", "真面目"}, }; // 中心の小さい円が、全体のどのくらいの割合か static double center_circle_ratio = 0.1; public void init () { int param_default[] = {3, 1, 2, 1, 3}; // パラメーターのセット param = new int[5]; for (int i = 0; i < 5; i++) { param[i] = param_default[i]; } // 名前 name = "川口 浩司"; // フォント // String fontname = "TimesRoman"; // String fontname = "Serif"; String fontname = getFont().getName(); int fontsize = 16; font = new Font(fontname, Font.PLAIN, fontsize); FontMetrics fm = getFontMetrics(font); font_ascend = fm.getAscent(); // パラメータ一覧の描画用の初期値の設定 paramtable_step = fm.getHeight() * 4 / 3; paramtable_top = new Point(fm.charWidth('■'), (int) (paramtable_step * 3 + font_ascend)); font_width = Math.max(fm.stringWidth(param_name[3] + param_value[3][3]), fm.stringWidth(param_name[4] + param_value[4][1])); // 円グラフ pie_radius = 48; pie_center = new Point(size().width - pie_radius - fm.charWidth('■') * 2, calcDrawYPoint(2) - font_ascend); // オフイメージ offimage = createImage(size().width, size().height); offgraphics = offimage.getGraphics(); } public void start() { redraw(true); } public void paint(Graphics g) { g.drawImage(offimage, 0, 0, this); } /** * 再描画する. * * @param pie 円グラフを再描画する場合は true を指定する. */ void redraw(boolean pie) { // 背景 offgraphics.setColor(new Color(128, 128, 128)); offgraphics.fillRect(0, 0, pie ? size().width : size().width - pie_center.x - pie_radius, size().height); drawStrings(offgraphics); if (pie) { drawPie(offgraphics); } repaint(); } /** * 名前とパラメータ文字を描画する */ void drawStrings(Graphics g) { // 名前 g.setFont(font); g.setColor(Color.white); g.drawString(name, paramtable_top.x, paramtable_top.y - paramtable_step * 2); // 名前の下の線 g.drawLine(paramtable_top.x, paramtable_top.y - paramtable_step - font_ascend, paramtable_top.x + font_width, paramtable_top.y - paramtable_step - font_ascend); // 各パラメータ for (int i = 0; i < 5; i++) { g.setColor(i == param_selected ? Color.red : Color.white); g.drawString(param_name[i] + param_value[i][param[i]], paramtable_top.x, calcDrawYPoint(i)); } } /** * 円グラフを描画する */ void drawPie(Graphics g) { // 座標 int xx, yy; // 円グラフの半径 int h2; // パラメータごとの円グラフ上の座標 int parx[], pary[]; // 中心の小さい円の座標 int smallx[], smally[]; // 角度ごとのsin, cos double cc[], cs[]; // その他 int i; // 円グラフ h2 = (int) (pie_radius * center_circle_ratio); parx = new int[5]; pary = new int[5]; smallx = new int[6]; smally = new int[6]; cc = new double[5]; cs = new double[5]; for (i = 16; i >= 0; i--) { // g.setColor(new Color(96, 96, 255)); g.setColor(new Color(6 * i, 6 * i, 255)); int noww = (int) (pie_radius * (i == 16 ? 1 : 0.4 + i / 28.0)); int nowh = (int) (pie_radius * (i == 16 ? 1 : 0.2 + i / 22.0)); g.fillArc(pie_center.x - noww, pie_center.y - nowh, noww * 2, nowh * 2, 0, 360); } // 5本の放射状の線の描画と、各種計算 for (i = 0; i < 5; i++) { int r; r = i * 72 + 270; cc[i] = Math.cos(r * Math.PI / 180); cs[i] = Math.sin(r * Math.PI / 180); smallx[i] = (int) (pie_center.x + cc[i] * h2); smally[i] = (int) (pie_center.y + cs[i] * h2); int parr = (int) (pie_radius * (param[i] / (4 + 4 * center_circle_ratio) + center_circle_ratio)); parx[i] = (int) (pie_center.x + cc[i] * parr); pary[i] = (int) (pie_center.y + cs[i] * parr); g.setColor(Color.white); g.drawLine(pie_center.x, pie_center.y, (int) (pie_center.x + cc[i] * pie_radius), (int) (pie_center.y + cs[i] * pie_radius)); } // 5角形 g.setColor(new Color(128, 64, 160)); g.fillPolygon(parx, pary, 5); // 5角形の上に、放射線を再描画 g.setColor(new Color(160, 96, 192)); for (i = 0; i < 5; i++) { g.drawLine(parx[i], pary[i], smallx[i], smally[i]); } // 中心の小さい円 smallx[5] = smallx[0]; smally[5] = smally[0]; g.drawPolygon(smallx, smally, 6); // ステータス欄 int parsum = 0; for (i = 0; i < 5; i++) { parsum += param[i]; } if (parsum == 0) { showStatus("(;_;)"); } else if (parsum == 20) { showStatus("(^^)(^^)(^^)(^^)(^^)"); } else { showStatus(null); } } /** * repaint時にちらつかないように */ public void update(Graphics g) { paint(g); } /** * マウス移動時の処理 */ public boolean mouseMove(Event evt, int x, int y) { int old_param_selected = param_selected; int i; for (i = 0; i < 5; i++) { int y0 = calcDrawYPoint(i) - font_ascend; if (x < pie_center.x - pie_radius && y >= y0 && y <= y0 + paramtable_step) { param_selected = i; break; } } if (i >= 5) { param_selected = -1; } if (old_param_selected != param_selected) { redraw(false); } return false; } /** * マウスが外に出た時の処理 */ public boolean mouseExit(Event evt, int x, int y) { mouseMove(evt, 0, 0); showStatus(null); return false; } /** * マウスをドラッグしている時の処理 */ public boolean mouseDrag(Event evt, int x, int y) { mouseMove(evt, x, y); return false; } /** * マウスを押した時の処理 */ public boolean mouseDown(Event evt, int x, int y) { if (param_selected != -1) { param[param_selected] = (param[param_selected] + 1) % 5; redraw(true); } return false; } /** * パラメータ一覧のY軸の描画位置を求める */ int calcDrawYPoint(int paramno) { return paramtable_top.y + paramtable_step * paramno; } }