+import java.awt.event.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+public class DrawArea extends JPanel implements MouseListener, MouseMotionListener, MouseWheelListener {
+ private int aDPI = 300;
+ /** По умолчанию панель будет размером с лист А4 */
+ private Dimension aSize = new Dimension(794, 1122);
+ /** Коэффициент зумирования */
+ private double scaleFactor = 1.0;
+ /** Размер сетки(во внутренник единицах измерения), если включена */
+ private int gridSize = 40;
+ /** Позиция курсора - позиция от которой рисуем(в логических, мировых координатах) */
+ private Point2D crossHairPosition = new Point2D.Double();
+ /** Привязывать ли курсор к сетке */
+ private boolean snapCursorToGrid = true;
+ /** Включаем выключаем сетку */
+ private boolean isGridEnabled = true;
+ /** Крест по центру экрана, если надо */
+ private boolean isCrossEnabled = true;
+ /** Сглаживание, если требуется */
+ private boolean isAnlialiasingEnabled = false;
+ /** Включен режим рисования(рисуется курсор для
+ * рисования на панели, иначе простой указатель) */
+ private boolean isDrawMode = true;
+ /** Включен ли режим просмотра для панели.
+ * В этом режиме запрещено редактировать или что-либо рисовать на панели,
+ * события мыши и клавиатуры игнорируются, изображение на панели
+ * панорамируется(если необходимо) */
+ private boolean isViewMode = false;
+ /** Координата, на которой нажали кнопку */
+ private Point mousePressedPos;
+ //GridSize s = new GridSize(15, SizeMeasureUnits.MIL);
+ private AffineTransform at = new AffineTransform();
+ setPreferredSize(aSize);
+ System.out.println("Size w: " + aSize.width + " h: " + aSize.height);
+ addMouseMotionListener(this);
+ addMouseListener(this);
+ addMouseWheelListener(this);
+ public Dimension getPreferredSize() {
+ return new Dimension((int)(aSize.width*scaleFactor),
+ (int)(aSize.height*scaleFactor));
+ /** Переводит координаты окна в координаты панели(мировые координаты) */
+ private Point TranslateW2WCoordinates(int winX, int winY) {
+ Container parent = getParent();
+ point = SwingUtilities.convertPoint(parent, new Point(winX, winY), this);
+ public void setCenterInViewport() {
+ Container parent = getParent();
+ if (parent instanceof JViewport) {
+ JViewport port = (JViewport)parent;
+ Rectangle viewRect = port.getViewRect();
+ int width = getWidth();
+ int height = getHeight();
+ viewRect.x = (int) ((width - viewRect.width) / 2F - viewRect.x);
+ viewRect.y = (int) ((height - viewRect.height) / 2F - viewRect.y);
+ port.scrollRectToVisible(viewRect);
+ /** Находит ближайший узел сетки для установки курсора.
+ * curX, curY - координаты курсора в мировых координатах */
+ private Point getNearestGridPosition(int curX, int curY) {
+ int scaledGridSize = (int) Math.floor(gridSize * scaleFactor);
+ float cellx = (float) Math.floor(curX / scaledGridSize);
+ float celly = (float) Math.floor(curY / scaledGridSize);
+ int x = (int)Math.floor(cellx * scaledGridSize);
+ int y = (int)Math.floor(celly * scaledGridSize);
+ System.out.println("Grid size: " + gridSize + " ScaleFactor: " + scaleFactor + " Scaled grid size: " + scaledGridSize);
+ System.out.println("Cursor pos - x: " + curX + " y: " + curY);
+ System.out.println("Cell num - x: " + cellx + " y: " + celly);
+ System.out.println("CrossHairPos - x: " + x + " y: " + y);
+ System.out.println("--------------------");
+ return new Point(x, y);
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ Graphics2D g2d = (Graphics2D) g;
+ setBackground(Color.WHITE);
+ if(isAnlialiasingEnabled) {
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+ g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_GASP);
+ /* Prepare draw area */
+ int gridStep = (int) Math.floor(gridSize * scaleFactor);
+ g2d.setColor(new Color(235, 235, 235));
+ for(int i = 0; i < w; i += gridStep)
+ g2d.drawLine(i, 0, i, h);
+ for(int j = 0; j < h; j += gridStep)
+ g2d.drawLine(0, j , w, j);
+ g2d.setColor(Color.GRAY);
+ float[] dash = {2f, 0f, 2f};
+ Stroke oldStroke = g2d.getStroke();
+ BasicStroke bs = new BasicStroke(1, BasicStroke.CAP_BUTT,
+ BasicStroke.JOIN_ROUND, 1.0f, dash, 2f);
+ g2d.drawLine(getWidth()/2, 0, getWidth()/2, getHeight());
+ g2d.drawLine(0, getHeight()/2, getWidth(), getHeight()/2);
+ g2d.setStroke(oldStroke);
+ int cs = 12; // размер крестика-курсора в пикселях
+ g2d.setColor(Color.GRAY);
+ /* Координаты курсора в мировых координатах, приведем их к оконным */
+ int cx = (int)crossHairPosition.getX();
+ int cy = (int)crossHairPosition.getY();
+ Point p = SwingUtilities.convertPoint(this, new Point(cx, cy), getParent());
+ g2d.drawLine(p.x-cs/2, p.y, p.x+cs/2, p.y);
+ g2d.drawLine(p.x, p.y-cs/2, p.x, p.y+cs/2);
+ /* Отрисовываем всё остальное(рисуем модель) */
+ g2d.setColor(Color.WHITE);
+ g2d.fillRect(100, 100, 80, 160);
+ g2d.setColor(Color.BLACK);
+ g2d.drawRect(100, 100, 80, 160); */
+ public void setDPI(int dpi) {
+ public void setGridSize(int sizePx) {
+ public void setGridEnabled(boolean enabled) {
+ isGridEnabled = enabled;
+ public void setCrossEnabled(boolean enabled) {
+ isCrossEnabled = enabled;
+ public void setAntialiasingEnabled(boolean enabled) {
+ isAnlialiasingEnabled = enabled;
+ public void setViewModeEnabled(boolean enabled) {
+ /** Включает режим просмотра и панорамирует всё что нарисовано
+ * (чтобы оно влезло в вид) */
+ public void setViewModeEnabled(boolean enabled, boolean panning) {
+ /* Если включено панорамирование, перерисуем всё что есть
+ * предварительно отмасштабировав под размеры viewport-а */
+ /****** MOUSE EVENTS ******/
+ public void mouseClicked(MouseEvent me) {}
+ public void mousePressed(MouseEvent me) {
+ mousePressedPos = new Point(me.getPoint());
+ System.out.println("mousePressedPos " + mousePressedPos.x + "/" + mousePressedPos.y);
+ public void mouseReleased(MouseEvent me) {
+ public void mouseEntered(MouseEvent me) {}
+ public void mouseExited(MouseEvent me) {}
+ public void mouseDragged(MouseEvent me) {
+ if(SwingUtilities.isMiddleMouseButton(me)) {
+ if(mousePressedPos != null) {
+ JViewport port = (JViewport)getParent();
+ Rectangle viewRect = port.getViewRect();
+ int deltaX = mousePressedPos.x - me.getX();
+ int deltaY = mousePressedPos.y - me.getY();
+ scrollRectToVisible(viewRect);
+ public void mouseMoved(MouseEvent me) {
+ // в мировые координаты
+ Point p = SwingUtilities.convertPoint(getParent(), new Point(x, y), this);
+ JViewport port = (JViewport)getParent();
+ Point vp = port.getViewPosition();
+ //System.out.println( "view.x: " + x + " view.y: " + y +
+ // " / area.x: " + p.x + " area.y: " + p.y +
+ // " / vpos.x: " + vp.x + " vpos.y: " + vp.y);
+ // Привязываем курсор к узлам сетки
+ Point np = getNearestGridPosition(p.x, p.y);
+ crossHairPosition.setLocation(np.x, np.y);
+ crossHairPosition.setLocation(p.x, p.y);
+ public void mouseWheelMoved(MouseWheelEvent mwe) {
+ /* минус для изменения направления движения колесика при маштабировании, так удобнее */
+ scaleFactor += -(0.035 * mwe.getWheelRotation());
+ scaleFactor = Math.max(0.05, scaleFactor);
+ scaleFactor = Math.min(scaleFactor, 4);