Skip to content

Instantly share code, notes, and snippets.

@eckig
Last active November 21, 2017 17:57
Show Gist options
  • Save eckig/176b7c2a10048bb71f43 to your computer and use it in GitHub Desktop.
Save eckig/176b7c2a10048bb71f43 to your computer and use it in GitHub Desktop.
public class ResizableGrid extends Pane {
// This is to make the stroke be drawn 'on pixel'.
private static final double HALF_PIXEL_OFFSET = -0.5;
private final Canvas canvas = new Canvas();
private boolean needsLayout = false;
private final StyleableObjectProperty<Paint> gridColor = new StyleableObjectProperty<Paint>(
Color.rgb(222, 248, 255)) {
@Override
public CssMetaData<? extends Styleable, Paint> getCssMetaData() {
return StyleableProperties.GRID_COLOR;
}
@Override
public Object getBean() {
return ResizableGrid.this;
}
@Override
public String getName() {
return "gridColor";
}
@Override
protected void invalidated() {
needsLayout = true;
requestLayout();
}
};
private final StyleableObjectProperty<Number> gridSpacing = new StyleableObjectProperty<Number>(15) {
@Override
public CssMetaData<? extends Styleable, Number> getCssMetaData() {
return StyleableProperties.GRID_SPACING;
}
@Override
public Object getBean() {
return ResizableGrid.this;
}
@Override
public String getName() {
return "gridSpacing";
}
@Override
protected void invalidated() {
needsLayout = true;
requestLayout();
}
};
public ResizableGrid() {
getStyleClass().add("graph-grid");
getChildren().add(canvas);
}
@Override
protected void layoutChildren() {
final int top = (int) snappedTopInset();
final int right = (int) snappedRightInset();
final int bottom = (int) snappedBottomInset();
final int left = (int) snappedLeftInset();
final int width = (int) getWidth() - left - right;
final int height = (int) getHeight() - top - bottom;
final double spacing = gridSpacing.get().doubleValue();
canvas.setLayoutX(left);
canvas.setLayoutY(top);
if (width != canvas.getWidth() || height != canvas.getHeight() || needsLayout) {
canvas.setWidth(width);
canvas.setHeight(height);
GraphicsContext g = canvas.getGraphicsContext2D();
g.clearRect(0, 0, width, height);
g.setFill(gridColor.get());
final int hLineCount = (int) Math.floor((height + 1) / spacing);
final int vLineCount = (int) Math.floor((width + 1) / spacing);
for (int i = 0; i < hLineCount; i++) {
g.strokeLine(0, snap((i + 1) * spacing), width, snap((i + 1) * spacing));
}
for (int i = 0; i < vLineCount; i++) {
g.strokeLine(snap((i + 1) * spacing), 0, snap((i + 1) * spacing), height);
}
needsLayout = false;
}
}
private static double snap(double y) {
return ((int) y) + HALF_PIXEL_OFFSET;
}
/**
* @return The CssMetaData associated with this class, including the
* CssMetaData of its super classes.
*/
public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
return StyleableProperties.STYLEABLES;
}
@Override
public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
return getClassCssMetaData();
}
private static class StyleableProperties {
private static final CssMetaData<ResizableGrid, Paint> GRID_COLOR = new CssMetaData<ResizableGrid, Paint>(
"-graph-grid-color", PaintConverter.getInstance()) {
@Override
public boolean isSettable(ResizableGrid node) {
return !node.gridColor.isBound();
}
@Override
public StyleableProperty<Paint> getStyleableProperty(ResizableGrid node) {
return node.gridColor;
}
};
private static final CssMetaData<ResizableGrid, Number> GRID_SPACING = new CssMetaData<ResizableGrid, Number>(
"-graph-grid-spacing", SizeConverter.getInstance()) {
@Override
public boolean isSettable(ResizableGrid node) {
return !node.gridSpacing.isBound();
}
@Override
public StyleableProperty<Number> getStyleableProperty(ResizableGrid node) {
return node.gridSpacing;
}
};
private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES;
static {
List<CssMetaData<? extends Styleable, ?>> styleables = new ArrayList<CssMetaData<? extends Styleable, ?>>(
Pane.getClassCssMetaData());
styleables.add(GRID_COLOR);
styleables.add(GRID_SPACING);
STYLEABLES = Collections.unmodifiableList(styleables);
}
}
}
@ganczar
Copy link

ganczar commented Nov 21, 2017

Thanks Steffen - works like a charm.
I think there should be g.setStroke instead of g.setFill for g.strokeLine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment