I'm trying to draw a diagram which exceeds the Raster class' limit of 46340 x 46340. My diagram is 2030000 x 240000 (with the help of JScrollPane). Is it possible to create several split up BufferedImages so that I can draw my diagram onto them piece by piece?
CodePudding user response:
So, based on you previous code, encapsulate the data model into a stand alone class, then create a "view model" which takes the data model and generates the "virtual" representation and caches this information.
Then, simple render the "view model" - this way all the computation overhead is done and not repeated.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.LinkedList;
import java.util.Objects;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Scrollable;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new JScrollPane(new TestPane(new ViewModel(new DataModel()))));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel implements Scrollable {
private ViewModel viewModel;
public TestPane(ViewModel viewModel) {
this.viewModel = viewModel;
Font currentFont = getFont();
Font newFont = currentFont.deriveFont(currentFont.getSize() * 1F);
setFont(newFont);
setBackground(Color.WHITE);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
for (Coord coord : viewModel.getNodeCoords()) {
g2d.setColor(Color.RED);
g2d.fillOval(coord.getXCoord() - 2, coord.getYCoord() - 2, 10, 10);
if (coord.getName() != null) {
g2d.setColor(Color.BLACK);
g2d.drawString(coord.getName(), coord.getXCoord(), coord.getYCoord());
}
}
for (Connection connection : viewModel.getConnections()) {
Point from = connection.getFrom();
Point to = connection.getTo();
g.drawLine(from.x, from.y, to.x, to.y);
}
g2d.dispose();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(2030000, 200000);
}
@Override
public Dimension getPreferredScrollableViewportSize() {
return new Dimension(400, 400);
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 32;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 32;
}
@Override
public boolean getScrollableTracksViewportWidth() {
return false;
}
@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
public class DataModel {
private LinkedList<Integer> vNodes = new LinkedList<>();
private LinkedList<Integer> vLevelWidth = new LinkedList<>();
private LinkedList<Integer> potentMoveSize = new LinkedList<>();
public DataModel() {
for (int i = 0; i < 10270; i ) {
vNodes.add(i);
}
vLevelWidth.add(10);
vLevelWidth.add(180);
vLevelWidth.add(1440);
vLevelWidth.add(8640);
for (int i = 0; i < 10; i ) {
potentMoveSize.add(18);
}
for (int i = 0; i < 180; i ) {
potentMoveSize.add(8);
}
for (int i = 0; i < 1440; i ) {
potentMoveSize.add(6);
}
potentMoveSize.add(10);
}
public LinkedList<Integer> getPotentMoveSize() {
return potentMoveSize;
}
public LinkedList<Integer> getVLevelWidth() {
return vLevelWidth;
}
public LinkedList<Integer> getVNodes() {
return vNodes;
}
}
public class Connection {
private Point from;
private Point to;
public Connection(Point from, Point to) {
this.from = from;
this.to = to;
}
public Point getFrom() {
return from;
}
public Point getTo() {
return to;
}
}
public class Coord {
private String name;
private Integer x, y, value;
public Coord(String name, Integer x, Integer y) {
this.x = x;
this.y = y;
}
public String getName() {
return name;
}
public Integer getXCoord() {
return x;
}
public Integer getYCoord() {
return y;
}
public Integer getValue() {
return value;
}
}
public class ViewModel {
private LinkedList<Coord> nodeCoords = new LinkedList<>();
private LinkedList<Connection> connections = new LinkedList<>();
public ViewModel(DataModel model) {
LinkedList<Integer> potentMoveSize = new LinkedList<>(model.getPotentMoveSize());
LinkedList<Integer> vLevelWidth = new LinkedList<>(model.getVLevelWidth());
LinkedList<Integer> vNodes = new LinkedList<>(model.getVNodes());
nodeCoords.add(new Coord("0", 2030000 / 2, 10));
Integer height = 4;
Integer heightIntervals = 200000 / (height 1);
for (int i = 0; i < height; i ) {
for (int j = 0; j < vLevelWidth.size(); j ) {
Integer fullWidth = vLevelWidth.get(j);
Integer nodeCount = 0;
Integer widthInterval = (2030000 - 150) / fullWidth;
for (int k = 0; k < vNodes.size(); k ) {
nodeCoords.add(new Coord(
"k" 0 0 "R" 0 0 "K" 0 0 ";",
widthInterval * (k 1),
heightIntervals * (i 1))
);
nodeCount ;
if (Objects.equals(nodeCount, fullWidth)) {
break;
}
}
for (int k = 0; k < nodeCount; k ) {
vNodes.removeFirst();
}
if (Objects.equals(nodeCount, fullWidth)) {
vLevelWidth.removeFirst();
break;
}
}
}
LinkedList<Point> froms = new LinkedList<>();
LinkedList<Point> tos = new LinkedList<>();
for (int i = 0; i < nodeCoords.size() - (model.getVLevelWidth().getLast()); i ) // everything except bottom row of nodes
{
froms.add(new Point(nodeCoords.get(i).getXCoord(), nodeCoords.get(i).getYCoord()));
}
for (int i = 1; i < nodeCoords.size(); i ) {
tos.add(new Point(nodeCoords.get(i).getXCoord(), nodeCoords.get(i).getYCoord()));
}
Integer connectedCount;
for (int i = 0; i < froms.size(); i ) {
connectedCount = 0;
for (int j = 0; j < tos.size(); j ) {
connections.add(new Connection(froms.get(i), tos.get(j)));
connectedCount ;
if (j 1 == potentMoveSize.get(0)) {
potentMoveSize.removeFirst();
for (int k = 0; k < connectedCount; k ) {
tos.removeFirst();
}
break;
}
}
}
}
public LinkedList<Coord> getNodeCoords() {
return nodeCoords;
}
public LinkedList<Connection> getConnections() {
return connections;
}
}
}
The above had no issues with scrolling for me, although I had many issues with actually trying to view the output - personally, I think the distance between nodes is WAY to large, but that's something you need to work out - I'd start with calculating the model and then working out the size you need to display instead of starting with the size you want and trying to fit the model into it.
If you have issues scrolling, then you could look at reducing the amount your are rendering by looking at the current clip rectangle and only rendering those elements which are actually currently displayed.
LinkedList
is also not very good at "random" access, it's best for linear access, so keep that in mind as well.