package canvastest; import javafx.application.Application; import javafx.event.EventHandler; import javafx.geometry.Bounds; import javafx.scene.Group; import javafx.scene.Scene; import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.effect.BlendMode; import javafx.scene.effect.GaussianBlur; import javafx.scene.input.MouseEvent; import javafx.scene.paint.Color; import javafx.scene.paint.Paint; import javafx.scene.shape.ArcType; import javafx.scene.shape.Rectangle; import javafx.scene.shape.StrokeLineJoin; import javafx.scene.text.Font; import javafx.scene.text.FontWeight; import javafx.scene.text.Text; import javafx.stage.Stage; public class CombineRenderModifiersTest extends Application { public static void main(String[] args) { launch(args); } enum RenderType { FILL_RECT, STROKE_RECT, FILL_OVAL, STROKE_OVAL, FILL_ROUNDRECT, STROKE_ROUNDRECT, FILL_ARC, STROKE_ARC, FILL_STRING, STROKE_STRING, FILL_SHAPE, STROKE_SHAPE, } Canvas canvases[]; Text labels[]; int renderIndex; @Override public void start(Stage primaryStage) { primaryStage.setTitle("Multiple rendering modifiers Canvas Test"); Group root = new Group(); canvases = new Canvas[32]; labels = new Text[32]; for (int i = 0; i < 32; i++) { double x = 10 + (i & 0x7) * 210; double y = 20 + (i >> 3) * 220; Canvas c = new Canvas(200, 200); c.setTranslateX(x); c.setTranslateY(y); canvases[i] = c; Rectangle r1 = new Rectangle(x-10, y-20, 220, 240); r1.setFill(Color.gray(0.85)); Rectangle r2 = new Rectangle(x, y, 200, 200); r2.setFill(Color.WHITE); Text t = new Text(); t.setY(y-5); labels[i] = t; root.getChildren().addAll(r1, r2, c, t); } Scene scene = new Scene(root); Text footer = new Text("Click in window to change shape type"); footer.setFont(Font.font(null, FontWeight.BOLD, 18)); Bounds b = footer.getBoundsInLocal(); double cx = (b.getMinX() + b.getMaxX()) / 2.0; footer.xProperty().bind(scene.widthProperty().divide(2.0).subtract(cx)); footer.yProperty().bind(scene.heightProperty().subtract(5)); root.getChildren().add(footer); primaryStage.setScene(scene); primaryStage.show(); scene.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler() { @Override public void handle(MouseEvent arg0) { renderIndex++; rerender(); } }); rerender(); } private void rerender() { RenderType types[] = RenderType.values(); RenderType renderType = types[renderIndex % types.length]; for (int i = 0; i < 32; i++) { boolean doBlend = (i & 1) != 0; boolean doClip = (i & 2) != 0; boolean doOpacity = (i & 4) != 0; boolean doEffect = (i & 8) != 0; boolean doTransform = (i & 16) != 0; Canvas c = canvases[i]; render(c, renderType, doBlend, doClip, doEffect, doTransform, doOpacity); String label = ""; if (doClip) label += ", clip"; if (doEffect) label += ", blur"; if (doTransform) label += ", rotate"; if (doOpacity) label += ", ea"; if (doBlend) { label = "DIFF" + label; } else { if (label.length() == 0) { label = "SRC_OVER, alpha=0.75"; } else { label = label.substring(2); } } Text t = labels[i]; t.setText(label); t.setX(0); Bounds bounds = t.getBoundsInLocal(); double cx = (bounds.getMinX() + bounds.getMaxX()) / 2.0; t.setX(c.getTranslateX() + 100 - cx); } } private static void render(Canvas c, RenderType renderType, boolean doBlend, boolean doClip, boolean doEffect, boolean doTransform, boolean doOpacity) { GraphicsContext gc = c.getGraphicsContext2D(); gc.save(); gc.clearRect(0, 0, 200, 200); gc.setLineWidth(renderType == RenderType.STROKE_STRING ? 6 : 20); gc.setLineJoin(StrokeLineJoin.ROUND); gc.setFont(Font.font("sans-serif", FontWeight.BOLD, 90)); Paint p = Color.rgb(0, 0, 255, 0.75); gc.setFill(p); gc.setStroke(p); if (doBlend) { gc.setGlobalBlendMode(BlendMode.DIFFERENCE); } if (doClip) { gc.beginPath(); gc.arc(100, 100, 80, 80, 0, 360); gc.clip(); } if (doEffect) { gc.setEffect(new GaussianBlur(10)); } if (doTransform) { gc.translate(100, 100); gc.rotate(85); gc.translate(-100, -100); } if (doOpacity) { gc.setGlobalAlpha(0.8); } renderObj(gc, renderType, 10, 10, 90, 90); renderObj(gc, renderType, 40, 40, 90, 90); renderObj(gc, renderType, 70, 70, 90, 90); renderObj(gc, renderType, 100, 100, 90, 90); gc.restore(); } private static void renderObj(GraphicsContext gc, RenderType renderType, double x, double y, double w, double h) { switch (renderType) { case FILL_RECT: gc.fillRect(x, y, w, h); break; case STROKE_RECT: gc.strokeRect(x+10, y+10, w-20, h-20); break; case FILL_OVAL: gc.fillOval(x, y, w, h); break; case STROKE_OVAL: gc.strokeOval(x+10, y+10, w-20, h-20); break; case FILL_ROUNDRECT: gc.fillRoundRect(x, y, w, h, 10, 10); break; case STROKE_ROUNDRECT: gc.strokeRoundRect(x+10, y+10, w-20, h-20, 10, 10); break; case FILL_ARC: gc.fillArc(x, y, w, h, 75, 270, ArcType.ROUND); break; case STROKE_ARC: gc.strokeArc(x+10, y+10, w-20, h-20, 75, 270, ArcType.ROUND); break; case FILL_STRING: gc.fillText("FX", x, y+90); break; case STROKE_STRING: gc.strokeText("FX", x, y+90); break; case STROKE_SHAPE: x += 10; y += 10; w -= 20; h -= 20; // NOBREAK case FILL_SHAPE: gc.beginPath(); gc.moveTo(x, y); gc.bezierCurveTo(x+w*1/3, y+h*1/5, x+w*2/3, y-h*1/5, x+w, y); gc.lineTo(x+w, y+h); gc.quadraticCurveTo(x+w/2, y+h*3/4, x, y+h); gc.closePath(); if (renderType == RenderType.FILL_SHAPE) { gc.fill(); } else { gc.stroke(); } break; default: throw new InternalError("Unrecognized render type: "+renderType); } } }