/* * Copyright 2003-2012 Yusuke Yamamoto * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package samurai.swing; import java.awt.Color; import java.util.ArrayList; import java.util.List; import java.text.DecimalFormat; /*package*/ class PlotData { private List<double[/*double ydata[]*//*double x */]>[] datas; private String[] labels; private int size; private double[] maxY; private double[] maxX; private double[] minY; private boolean[] visible; private Color[] colors; private boolean initialized = false; private final int DATA_CHUNK_SIZE = 256; private int xDataIndex; /*package*/ boolean isInitialized() { return initialized; } /*package*/ PlotData() { } /*package*/ void setLabels(String[] labels) { this.labels = labels; this.initialized = true; this.datas = new List[labels.length + 1]; this.xDataIndex = labels.length; this.size = 0; this.maxY = new double[labels.length]; this.minY = new double[labels.length]; this.visible = new boolean[labels.length]; this.colors = new Color[labels.length]; for (int i = 0; i < labels.length; i++) { this.visible[i] = true; this.maxY[i] = 0; this.minY[i] = 0; this.colors[i] = DEFAULT_COLORS[i % DEFAULT_COLORS.length]; this.datas[i] = new ArrayList<double[]>(1); } this.datas[xDataIndex] = new ArrayList<double[]>(1); } /*package*/ double getMaxAt(int index) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } return maxY[index]; } /*package*/ double getMinAt(int index) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } return minY[index]; } /*package*/ int size() { if (!initialized) { throw new IllegalStateException("not yet initialized"); } return this.size; } /*package*/ int getLabelCount() { if (!initialized) { throw new IllegalStateException("not yet initialized"); } return labels.length; } /*package*/ Color getColorAt(int index) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } return this.colors[index]; } /*package*/ void setColorAt(int index, Color color) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } this.colors[index] = color; } /*package*/ double getValueAt(int index, int count) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } return datas[index].get(count / DATA_CHUNK_SIZE)[count % DATA_CHUNK_SIZE]; } /*package*/ void setMaxAt(int index, double max) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } this.maxY[index] = max; } /*package*/ void setMinAt(int index, double min) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } this.minY[index] = min; } /*package*/ String getLabelAt(int index) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } return this.labels[index]; } /*package*/ void setLabelAt(int index, String label) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } this.labels[index] = label; } /*package*/ void addValues(double x,double[] newDatas) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } int chunkIndex = size / DATA_CHUNK_SIZE; int leftover = size % DATA_CHUNK_SIZE; if ((leftover) == 0) { for (int i = 0; i < this.labels.length; i++) { this.datas[i].add(new double[DATA_CHUNK_SIZE]); } this.datas[xDataIndex].add(new double[DATA_CHUNK_SIZE]); } for (int i = 0; i < this.labels.length; i++) { if (maxY[i] < newDatas[i]) { maxY[i] = newDatas[i]; } if (minY[i] > newDatas[i]) { minY[i] = newDatas[i]; } this.datas[i].get(chunkIndex) [leftover] = newDatas[i]; } this.datas[xDataIndex].get(chunkIndex) [leftover] = x; size++; } /*package*/ void addValues(double[] newDatas) { addValues(size,newDatas); } private final Color[] DEFAULT_COLORS = new Color[]{ Color.YELLOW, Color.BLUE, Color.CYAN, Color.GRAY, Color.GREEN, Color.MAGENTA, Color.ORANGE, Color.WHITE, }; /*package*/ boolean isVisibleAt(int index) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } return this.visible[index]; } /*package*/ void setVisibleAt(int index, boolean newVisible) { if (!initialized) { throw new IllegalStateException("not yet initialized"); } this.visible[index] = newVisible; } private Color background = Color.BLACK; private Color gridColor = new Color(0, 70, 0); private final int GRID_INTERVAL = 10; private DecimalFormat format = new DecimalFormat("####0.0#############################"); public void drawGraph(GraphCanvas c, int x, int y, int width, int height,int scroll) { int maxY = y + height; int maxX = x + width; c.setColor(background); c.fillRect(x, y, width, height); c.setColor(gridColor); if (isInitialized()) { drawGrid(c, x, y, width, scroll, maxY, maxX); drawLegends(c, width, height, maxY); if (size() > 0) { for (int i = 0; i < getLabelCount(); i++) { if (isVisibleAt(i)) { c.setColor(getColorAt(i)); int index; int drawWidth; if(width >= size()){ drawWidth = size(); index = size() - 1; }else{ drawWidth = width; index = scroll + width - 1; if(index > size()){ index = size() - 1; } } int drawX = width - drawWidth; int lastY = maxY - (int) ((double) height / getMaxAt(i) * getValueAt(i, index - drawWidth+1)); for (int j = index - drawWidth+2; j < index; j++) { // for (int j = --index; j >= 0; j--) { int drawY = maxY - (int) ((double) height / getMaxAt(i) * getValueAt(i, j)); c.drawLine(drawX, lastY, drawX + 1, drawY); lastY = drawY; drawX++; } } } } } } private void drawLegends(GraphCanvas c, int width, int height, int maxY) { int fontHeight = c.getFontHeight() + 2; for (int i = 0; i < getLabelCount(); i++) { if (isVisibleAt(i)) { c.setColor(getColorAt(i)); c.drawString(getLabelAt(i) + ":" + format.format(getMaxAt(i)), 5, fontHeight * (i + 1)); c.drawString(format.format(getMinAt(i)), 5, height - 5 - fontHeight * (getLabelCount() - 1) + fontHeight * i); //draw latest value if (size() > 0) { String currentValue = format.format(getValueAt(i, size() - 1)); int currentValueY = maxY - (int) ((double) height / getMaxAt(i) * getValueAt(i, size() - 1)); currentValueY = fontHeight > currentValueY ? fontHeight : currentValueY; c.drawString(currentValue, width - c.getStringWidth(currentValue) - 5, currentValueY); } } } } private void drawGrid(GraphCanvas c, int x, int y, int width, int scroll, int maxY, int maxX) { //draw grid //horizontal lines for (int i = maxY - (GRID_INTERVAL - 1); i > y; i -= GRID_INTERVAL) { c.drawLine(x, i, maxX, i); } //vertical lines int gridx; if (width >= size()) { gridx = GRID_INTERVAL - ((size() - width) % GRID_INTERVAL); } else { gridx = GRID_INTERVAL - ((size() + scroll) % GRID_INTERVAL); } for (int i = gridx; i < maxX; i += GRID_INTERVAL) { c.drawLine(i, y, i, maxY); } } }