下面列出了怎么用javafx.scene.shape.StrokeType的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public void updateChanges()
{
super.updateChanges();
if (dirty_size.checkAndClear())
{
jfx_node.setWidth(model_widget.propWidth().getValue());
jfx_node.setHeight(model_widget.propHeight().getValue());
jfx_node.setArcWidth(2 * model_widget.propCornerWidth().getValue());
jfx_node.setArcHeight(2 * model_widget.propCornerHeight().getValue());
}
if (dirty_look.checkAndClear())
{
jfx_node.setMouseTransparent(ignore_mouse);
jfx_node.setFill(background);
jfx_node.setStroke(line_color);
jfx_node.setStrokeWidth(model_widget.propLineWidth().getValue());
jfx_node.setStrokeType(StrokeType.INSIDE);
}
}
private void initGraphics() {
if (Double.compare(getPrefWidth(), 0.0) <= 0 || Double.compare(getPrefHeight(), 0.0) <= 0 || Double.compare(getWidth(), 0.0) <= 0 ||
Double.compare(getHeight(), 0.0) <= 0) {
if (getPrefWidth() > 0 && getPrefHeight() > 0) {
setPrefSize(getPrefWidth(), getPrefHeight());
} else {
setPrefSize(PREFERRED_WIDTH, PREFERRED_HEIGHT);
}
}
getStyleClass().add("indicator");
ring = new Circle(PREFERRED_WIDTH * 0.5);
ring.setStrokeType(StrokeType.INSIDE);
ring.setStrokeWidth(PREFERRED_WIDTH * 0.078125);
ring.setStroke(getRingColor());
ring.setFill(Color.TRANSPARENT);
dot = new Circle(PREFERRED_WIDTH * 0.3125);
dot.setFill(getDotOnColor());
pane = new Pane(ring, dot);
getChildren().setAll(pane);
}
private void refreshShape() {
Node shape = ZestProperties.getShape(getContent());
if (this.shape != shape && shape != null) {
getVisual().getChildren().remove(this.shape);
this.shape = shape;
if (shape instanceof GeometryNode) {
((GeometryNode<?>) shape).setStrokeType(StrokeType.INSIDE);
} else if (shape instanceof Shape) {
((Shape) shape).setStrokeType(StrokeType.INSIDE);
}
if (!shape.getStyleClass().contains(CSS_CLASS_SHAPE)) {
shape.getStyleClass().add(CSS_CLASS_SHAPE);
}
getVisual().getChildren().add(0, shape);
}
}
/**
* Ensures setting/resizing the geometry will resize the visuals
*/
@Test
public void resizeGeometryOnResize() {
GeometryNode<RoundedRectangle> n = new GeometryNode<>();
n.setFill(Color.RED);
n.setStrokeWidth(5);
n.setStrokeType(StrokeType.OUTSIDE);
n.setGeometry(new RoundedRectangle(30, 40, 30, 40, 20, 20));
n.resize(30, 40);
assertEquals(n.getGeometry().getBounds().getWidth(), 20, 0);
assertEquals(n.getGeometry().getBounds().getHeight(), 30, 0);
assertEquals(30.0, n.getWidth(), 0);
assertEquals(40.0, n.getHeight(), 0);
assertEquals(25, n.getLayoutX(), 0);
assertEquals(35, n.getLayoutY(), 0);
assertEquals(30, n.getGeometry().getBounds().getX(), 0);
assertEquals(40, n.getGeometry().getBounds().getY(), 0);
}
@Test
public void resizeRelocateOnStrokeWidthAndTypeChange() {
GeometryNode<RoundedRectangle> n = new GeometryNode<>();
n.setGeometry(new RoundedRectangle(30, 40, 30, 40, 20, 20));
assertEquals(29.5, n.getLayoutX(), 0);
assertEquals(39.5, n.getLayoutY(), 0);
assertEquals(30, n.getGeometry().getBounds().getX(), 0);
assertEquals(40, n.getGeometry().getBounds().getY(), 0);
n.setFill(Color.RED);
n.setStrokeWidth(5);
n.setStrokeType(StrokeType.OUTSIDE);
assertEquals(n.getGeometry().getBounds().getWidth(), 30, 0);
assertEquals(n.getGeometry().getBounds().getHeight(), 40, 0);
assertEquals(40.0, n.getWidth(), 0);
assertEquals(50.0, n.getHeight(), 0);
assertEquals(25, n.getLayoutX(), 0);
assertEquals(35, n.getLayoutY(), 0);
assertEquals(30, n.getGeometry().getBounds().getX(), 0);
assertEquals(40, n.getGeometry().getBounds().getY(), 0);
}
@Test
public void relocateGeometryOnRelocate() {
GeometryNode<RoundedRectangle> n = new GeometryNode<>();
n.setFill(Color.RED);
n.setStrokeWidth(5);
n.setStrokeType(StrokeType.OUTSIDE);
n.setGeometry(new RoundedRectangle(30, 40, 30, 40, 20, 20));
n.relocate(30, 40);
assertEquals(n.getGeometry().getBounds().getX(), 35, 0);
assertEquals(n.getGeometry().getBounds().getY(), 45, 0);
assertEquals(30.0, n.getLayoutX(), 0);
assertEquals(40.0, n.getLayoutY(), 0);
assertEquals(n.getGeometry().getBounds().getWidth(), 30, 0);
assertEquals(n.getGeometry().getBounds().getHeight(), 40, 0);
assertEquals(40.0, n.getWidth(), 0);
assertEquals(50.0, n.getHeight(), 0);
}
@Override
public void doRefreshVisual(GeometryNode<IGeometry> visual) {
if (getAnchoragesUnmodifiable().size() != 1) {
return;
}
IGeometry feedbackGeometry = getFeedbackGeometry();
if (feedbackGeometry == null) {
return;
}
// FIXME: Investigate why the StrokeType needs to be set before setting
// the geometry in order to prevent a vertical offset.
if (feedbackGeometry instanceof ICurve) {
// stroke centered
visual.setStrokeType(StrokeType.CENTERED);
} else {
// stroke outside
visual.setStrokeType(StrokeType.OUTSIDE);
}
visual.setGeometry(feedbackGeometry);
}
private void init()
{
Group g = new Group();
mCircle = new Circle(0,0,40);
mCircle.setFill(Color.WHITE);
mCircle.setStrokeWidth(3);
mCircle.setStrokeMiterLimit(10);
mCircle.setStrokeType(StrokeType.CENTERED);
mCircle.setStroke(Color.valueOf("0x333333"));
Circle inner = new Circle(0,0,8);
inner.setFill(Color.valueOf("0xFFFFFF00"));
inner.setStrokeWidth(4);
inner.setStrokeMiterLimit(10);
inner.setStrokeType(StrokeType.INSIDE);
inner.setStroke(Color.valueOf("0x000000"));
g.getChildren().addAll(mCircle, inner);
setAlignment(g, Pos.CENTER);
getChildren().add(g);
}
/**
* Convenience method for simple and default setup of zooming on an {@link XYChart} via a
* {@link ChartZoomManager}. Wraps the chart in the components required to implement zooming. The
* current implementation wraps the chart in a StackPane, which has the chart and a blue
* translucent rectangle as children. Returns the top level of the created components.
* <p>
* If the chart already has a parent, that parent must be a {@link Pane}, and the chart is
* replaced with the wrapping region, and the return value could be ignored. If the chart does
* not have a parent, the same wrapping node is returned, which will need to be added to some
* parent.
* <p>
* The chart's axes must both be a type of ValueAxis.
* <p>
* The wrapping logic does not seem to be perfect, in fact there is a special case to handle
* {@link BorderPane}s. If it's not found to be reliable, then create the wrapping components
* yourself (such as in the FXML), or setup zooming before adding it to a parent.
*
* @param mouseFilter EventHandler that consumes events that should not trigger a zoom action
*
* @return The top-level Region
*/
public static Region setupZooming( XYChart<?, ?> chart,
EventHandler<? super MouseEvent> mouseFilter ) {
StackPane chartPane = new StackPane();
if ( chart.getParent() != null )
JFXUtil.replaceComponent( chart, chartPane );
Rectangle selectRect = new Rectangle( 0, 0, 0, 0 );
selectRect.setFill( Color.DODGERBLUE );
selectRect.setMouseTransparent( true );
selectRect.setOpacity( 0.3 );
selectRect.setStroke( Color.rgb( 0, 0x29, 0x66 ) );
selectRect.setStrokeType( StrokeType.INSIDE );
selectRect.setStrokeWidth( 3.0 );
StackPane.setAlignment( selectRect, Pos.TOP_LEFT );
chartPane.getChildren().addAll( chart, selectRect );
ChartZoomManager zoomManager = new ChartZoomManager( chartPane, selectRect, chart );
zoomManager.setMouseFilter( mouseFilter );
zoomManager.start();
return chartPane;
}
private void populateCells(Group root, final SpriteView.Mary mary) {
// Gratuitous use of lambdas to do nested iteration!
Group cells = new Group();
IntStream.range(0, HORIZONTAL_CELLS).mapToObj(i ->
IntStream.range(0, VERTICAL_CELLS).mapToObj(j -> {
Rectangle rect = new Rectangle(i * CELL_SIZE, j * CELL_SIZE, CELL_SIZE, CELL_SIZE);
rect.setFill(Color.rgb(0, 0, 0, 0));
rect.setStrokeType(StrokeType.INSIDE);
rect.setStroke(Color.BLACK);
rect.setOnMousePressed(e -> mary.moveTo(new Location(i, j)));
return rect;
})
).flatMap(s -> s).forEach(cells.getChildren()::add);
root.getChildren().add(cells);
}
private void drawHexagonMapContour(final GraphicsContext gc, final ContourDataSetCache lCache) {
final long start = ProcessingProfiler.getTimeStamp();
// process z quantisation to colour transform
final WritableImage image = localCache.convertDataArrayToImage(lCache.reduced, lCache.xSize, lCache.ySize, getColorGradient());
final int tileSize = Math.max(getMinHexTileSizeProperty(), (int) lCache.xAxisWidth / lCache.xSize);
final int nWidthInTiles = (int) (lCache.xAxisWidth / (tileSize * Math.sqrt(3)));
final HexagonMap hexMap = new HexagonMap(tileSize, image, nWidthInTiles, (q, r, imagePixelColor, map) -> {
final Hexagon h = new Hexagon(q, r);
h.setFill(Color.TRANSPARENT); // contour being plotted
h.setStroke(imagePixelColor);
h.setStrokeType(StrokeType.CENTERED);
h.setStrokeWidth(1);
map.addHexagon(h);
});
localCache.add(image);
ProcessingProfiler.getTimeDiff(start, "drawHexagonMapContour - prepare");
final double scaleX = lCache.xDataPixelRange / lCache.xAxisWidth;
final double scaleY = lCache.yDataPixelRange / lCache.yAxisHeight;
gc.save();
gc.translate(lCache.xDataPixelMin, lCache.yDataPixelMin);
gc.scale(scaleX, scaleY);
hexMap.renderContour(gc.getCanvas());
gc.restore();
ProcessingProfiler.getTimeDiff(start, "drawHexagonMapContour");
}
protected void init() {
final int n = numberOfFlakesProperty().get();
List<PhysicalSnowFlake> list = new ArrayList<>(n);
if (snowProperty().get()) {
for (int i = 0; i < n; i++) {
final double radius = RND.Gaus(meanSizeProperty().get(), rmsSizeProperty().get());
final PhysicalSnowFlake circle = new PhysicalSnowFlake(radius, snowColorProperty().get()); // NOPMD
circle.setStrokeType(StrokeType.OUTSIDE);
circle.setStroke(Color.web("black", 0.16));
circle.init();
list.add(circle);
}
}
circles.getChildren().setAll(list);
}
public SimpleHSBColorPicker() {
getChildren().addAll(hsbRect,lightRect);
lightRect.setStroke(Color.GRAY);
lightRect.setStrokeType(StrokeType.OUTSIDE);
EventHandler<MouseEvent> ml = new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent e) {
double w = getWidth();
double h = getHeight();
double x = Math.min(w, Math.max(0, e.getX()));
double y = Math.min(h, Math.max(0, e.getY()));
double hue = (360/w)*x;
double vert = (1/h)*y;
double sat = 0;
double bright = 0;
if (vert<0.5) {
bright = 1;
sat = vert * 2;
} else {
bright = sat = 1- ((vert-0.5)*2);
}
// convert back to color
Color c = Color.hsb((int)hue,sat,bright);
color.set(c);
e.consume();
}
};
lightRect.setOnMouseDragged(ml);
lightRect.setOnMouseClicked(ml);
}
public SimpleHSBColorPicker() {
getChildren().addAll(hsbRect,lightRect);
lightRect.setStroke(Color.GRAY);
lightRect.setStrokeType(StrokeType.OUTSIDE);
EventHandler<MouseEvent> ml = new EventHandler<MouseEvent>() {
@Override public void handle(MouseEvent e) {
double w = getWidth();
double h = getHeight();
double x = Math.min(w, Math.max(0, e.getX()));
double y = Math.min(h, Math.max(0, e.getY()));
double hue = (360/w)*x;
double vert = (1/h)*y;
double sat = 0;
double bright = 0;
if (vert<0.5) {
bright = 1;
sat = vert * 2;
} else {
bright = sat = 1- ((vert-0.5)*2);
}
// convert back to color
Color c = Color.hsb((int)hue,sat,bright);
color.set(c);
e.consume();
}
};
lightRect.setOnMouseDragged(ml);
lightRect.setOnMouseClicked(ml);
}
@Override
public void updateChanges()
{
// Not using default handling of X/Y super.updateChanges();
if (dirty_position.checkAndClear())
{
if (model_widget.propVisible().getValue())
{
jfx_node.setVisible(true);
final int x = model_widget.propX().getValue();
final int y = model_widget.propY().getValue();
final int w = model_widget.propWidth().getValue();
final int h = model_widget.propHeight().getValue();
jfx_node.setCenterX(x + w/2);
jfx_node.setCenterY(y + h/2);
jfx_node.setRadiusX(w/2);
jfx_node.setRadiusY(h/2);
}
else
jfx_node.setVisible(false);
}
if (dirty_look.checkAndClear())
{
jfx_node.setFill(background);
jfx_node.setStroke(line_color);
jfx_node.setStrokeWidth(model_widget.propLineWidth().getValue());
jfx_node.setStrokeType(StrokeType.INSIDE);
}
}
private void resize() {
width = getWidth() - getInsets().getLeft() - getInsets().getRight();
height = getHeight() - getInsets().getTop() - getInsets().getBottom();
size = width < height ? width : height;
if (width > 0 && height > 0) {
pane.setMaxSize(size, size);
pane.relocate((getWidth() - size) * 0.5, (getHeight() - size) * 0.5);
ring.setCenterX(size * 0.5);
ring.setCenterY(size * 0.5);
ring.setRadius(size * 0.5);
ring.setStrokeWidth(size * 0.025);
ring.setStrokeType(StrokeType.INSIDE);
mask.setCenterX(size * 0.5);
mask.setCenterY(size * 0.5);
mask.setRadius(size * 0.45);
canvas.setWidth(size);
canvas.setHeight(size);
canvas.relocate(0, 0);
text.setFont(Fonts.robotoMedium(size * 0.25));
text.setY(size * 0.5);
text.setX((size - text.getLayoutBounds().getWidth()) * 0.5);
for( int i = 0 ; i < detail + 1 ; i++ ) {
Point p = particles.get(i);
p.x = size / (detail - 4) * (i - 2);
p.y = size * (1d - gauge.getCurrentValue());
p.originalX = p.x;
p.originalY = p.y;
}
}
}
@Override protected void resize() {
double width = gauge.getWidth() - gauge.getInsets().getLeft() - gauge.getInsets().getRight();
double height = gauge.getHeight() - gauge.getInsets().getTop() - gauge.getInsets().getBottom();
size = width < height ? width : height;
if (width > 0 && height > 0) {
pane.setMaxSize(size, size);
pane.relocate((width - size) * 0.5, (height - size) * 0.5);
colorRing.setCenterX(size * 0.5);
colorRing.setCenterY(size * 0.5);
colorRing.setRadius(size * 0.5);
colorRing.setStrokeWidth(size * 0.0075);
colorRing.setStrokeType(StrokeType.INSIDE);
bar.setCenterX(size * 0.5);
bar.setCenterY(size * 0.5);
bar.setRadiusX(size * 0.4135);
bar.setRadiusY(size * 0.4135);
bar.setStrokeWidth(size * 0.12);
separator.setStartX(size * 0.5);
separator.setStartY(size * 0.0275);
separator.setEndX(size * 0.5);
separator.setEndY(size * 0.145);
resizeTitleText();
resizeValueText();
resizeUnitText();
}
}
public static Node createLoadingNode () {
Circle c0 = new Circle(65);
c0.setFill(Color.TRANSPARENT);
c0.setStrokeWidth(0.0);
Circle c1 = new Circle(50);
c1.setFill(Color.TRANSPARENT);
c1.setStrokeType(StrokeType.INSIDE);
c1.setStrokeLineCap(StrokeLineCap.BUTT);
c1.getStrokeDashArray().addAll(78.54); // 50 * 2 * 3.1416 / 4
c1.setCache(true);
c1.setCacheHint(CacheHint.ROTATE);
c1.getStyleClass().add("loading-circle");
setRotate(c1, true, 440.0, 10);
Circle c2 = new Circle(40);
c2.setFill(Color.TRANSPARENT);
c2.setStrokeType(StrokeType.INSIDE);
c2.setStrokeLineCap(StrokeLineCap.BUTT);
c2.getStrokeDashArray().addAll(41.89); // 40 * 2 * 3.1416 / 6
c2.setCache(true);
c2.setCacheHint(CacheHint.ROTATE);
c2.getStyleClass().add("loading-circle");
setRotate(c2, true, 360.0, 14);
Circle c3 = new Circle(30);
c3.setFill(Color.TRANSPARENT);
c3.setStrokeType(StrokeType.INSIDE);
c3.setStrokeLineCap(StrokeLineCap.BUTT);
c3.getStyleClass().add("loading-circle");
Group g = new Group(c0, c1, c2, c3);
g.getStylesheets().add(Dialogs.class.getResource("/com/adr/helloiot/styles/loading.css").toExternalForm());
return g;
}
public static Node createSmallLoadingNode () {
Circle c0 = new Circle(45);
c0.setFill(Color.TRANSPARENT);
c0.setStrokeWidth(0.0);
Circle c2 = new Circle(40);
c2.setFill(Color.TRANSPARENT);
c2.setStrokeType(StrokeType.INSIDE);
c2.setStrokeLineCap(StrokeLineCap.BUTT);
c2.getStrokeDashArray().addAll(41.89); // 40 * 2 * 3.1416 / 6
c2.setCache(true);
c2.setCacheHint(CacheHint.ROTATE);
c2.getStyleClass().add("loading-circle");
setRotate(c2, true, 360.0, 14);
Circle c3 = new Circle(30);
c3.setFill(Color.TRANSPARENT);
c3.setStrokeType(StrokeType.INSIDE);
c3.setStrokeLineCap(StrokeLineCap.BUTT);
c3.getStyleClass().add("loading-circle");
Group g = new Group(c0, c2, c3);
g.getStylesheets().add(Dialogs.class.getResource("/com/adr/helloiot/styles/loading.css").toExternalForm());
return g;
}
/**
* Returns the layout-bounds of the given {@link Node}, which might be
* adjusted to ensure that it exactly fits the visualization.
*
* @param node
* The {@link Node} to retrieve the (corrected) layout-bounds of.
* @return A {@link Rectangle} representing the (corrected) layout-bounds.
*/
public static Rectangle getShapeBounds(Node node) {
Bounds layoutBounds = node.getLayoutBounds();
// XXX: Polygons don't paint exactly to their layout bounds but remain
// 0.5 pixels short in case they have a stroke and stroke type is
// CENTERED or OUTSIDE (see
// https://bugs.openjdk.java.net/browse/JDK-8145499).
double offset = 0;
if (node instanceof Polygon && ((Polygon) node).getStroke() != null
&& ((Polygon) node).getStrokeType() != StrokeType.INSIDE) {
offset = 0.5;
}
return FX2Geometry.toRectangle(layoutBounds).shrink(offset, offset,
offset, offset);
}
private double getStrokeOffset() {
double offset = 0;
if (geometricShape.getStroke() != null
&& geometricShape.getStrokeType() != StrokeType.INSIDE) {
offset = (geometricShape.getStrokeType() == StrokeType.CENTERED
? 0.5
: 1) * geometricShape.getStrokeWidth();
}
return offset;
}
/**
* Creates the shape used to display the node's border and background.
*
* @return The newly created {@link Shape}.
*/
private Node createDefaultShape() {
GeometryNode<?> shape = new GeometryNode<>(new org.eclipse.gef.geometry.planar.Rectangle());
shape.setUserData(DEFAULT_SHAPE_ROLE);
shape.getStyleClass().add(CSS_CLASS_SHAPE);
shape.setFill(new LinearGradient(0, 0, 1, 1, true, CycleMethod.REFLECT,
Arrays.asList(new Stop(0, new Color(1, 1, 1, 1)))));
shape.setStroke(new Color(0, 0, 0, 1));
shape.setStrokeType(StrokeType.INSIDE);
return shape;
}
/**
* Ensures setting/resizing the geometry will resize the visuals
*/
@Test
public void resizeOnGeometryChange() {
GeometryNode<RoundedRectangle> n = new GeometryNode<>();
n.setFill(Color.RED);
n.setStrokeWidth(5);
n.setStrokeType(StrokeType.OUTSIDE);
n.setGeometry(new RoundedRectangle(30, 40, 30, 40, 20, 20));
assertEquals(n.getGeometry().getBounds().getWidth(), 30, 0);
assertEquals(n.getGeometry().getBounds().getHeight(), 40, 0);
assertEquals(40.0, n.getWidth(), 0);
assertEquals(50.0, n.getHeight(), 0);
assertEquals(25, n.getLayoutX(), 0);
assertEquals(35, n.getLayoutY(), 0);
assertEquals(30, n.getGeometry().getBounds().getX(), 0);
assertEquals(40, n.getGeometry().getBounds().getY(), 0);
n.resizeGeometry(50, 60);
assertEquals(n.getGeometry().getBounds().getWidth(), 50, 0);
assertEquals(n.getGeometry().getBounds().getHeight(), 60, 0);
assertEquals(60.0, n.getWidth(), 0);
assertEquals(70.0, n.getHeight(), 0);
assertEquals(25, n.getLayoutX(), 0);
assertEquals(35, n.getLayoutY(), 0);
assertEquals(30, n.getGeometry().getBounds().getX(), 0);
assertEquals(40, n.getGeometry().getBounds().getY(), 0);
}
@Test
public void resizePolylineNode() {
GeometryNode<Polyline> n = new GeometryNode<>();
// Polyline: (19.02538299560547, 30.438175201416016) -> (19.02538299560547,
// 108.58389282226562)
n.setGeometry(new Polyline(19.02538299560547, 30.438175201416016, 19.02538299560547, 108.58389282226562));
n.setStrokeWidth(3.5);
n.setStrokeType(StrokeType.CENTERED);
}
@Test
public void relocateOnGeometryChange() {
GeometryNode<RoundedRectangle> n = new GeometryNode<>();
n.setFill(Color.RED);
n.setStrokeWidth(5);
n.setStrokeType(StrokeType.OUTSIDE);
n.setGeometry(new RoundedRectangle(30, 40, 30, 40, 20, 20));
assertEquals(n.getGeometry().getBounds().getX(), 30, 0);
assertEquals(n.getGeometry().getBounds().getY(), 40, 0);
assertEquals(25.0, n.getLayoutX(), 0);
assertEquals(35.0, n.getLayoutY(), 0);
assertEquals(n.getGeometry().getBounds().getWidth(), 30, 0);
assertEquals(n.getGeometry().getBounds().getHeight(), 40, 0);
assertEquals(40.0, n.getWidth(), 0);
assertEquals(50.0, n.getHeight(), 0);
n.relocateGeometry(50, 60);
assertEquals(n.getGeometry().getBounds().getX(), 50, 0);
assertEquals(n.getGeometry().getBounds().getY(), 60, 0);
assertEquals(45.0, n.getLayoutX(), 0);
assertEquals(55.0, n.getLayoutY(), 0);
assertEquals(n.getGeometry().getBounds().getWidth(), 30, 0);
assertEquals(n.getGeometry().getBounds().getHeight(), 40, 0);
assertEquals(40.0, n.getWidth(), 0);
assertEquals(50.0, n.getHeight(), 0);
}
@Test
public void getGeometricOutline() {
// Shape
javafx.scene.shape.Rectangle shape = new javafx.scene.shape.Rectangle(5, 10, 30, 40);
shape.setStroke(Color.RED);
shape.setStrokeWidth(3);
shape.setStrokeType(StrokeType.OUTSIDE);
shape.relocate(30, 40);
IGeometry geometricOutline = NodeUtils.getGeometricOutline(shape);
assertTrue(geometricOutline instanceof Rectangle);
// the geometry is returned in the local coordinates of the Shape (the
// stroke is outside), thus the X and Y values are preserved
assertEquals(new Rectangle(5, 10, 30, 40), geometricOutline);
// translating it into parent coordinates returns the relocate values
// including the stroke offset
assertEquals(new Rectangle(33, 43, 30, 40), NodeUtils.localToParent(shape, geometricOutline).getBounds());
// GeometryNode
GeometryNode<Rectangle> geometryNode = new GeometryNode<>();
geometryNode.setStroke(Color.RED);
geometryNode.setStrokeWidth(3);
geometryNode.setStrokeType(StrokeType.OUTSIDE);
geometryNode.setGeometry(new Rectangle(0, 0, 30, 40));
geometryNode.relocate(30, 40);
geometricOutline = NodeUtils.getGeometricOutline(geometryNode);
assertTrue(geometricOutline instanceof Rectangle);
// the geometric is returned in the local coordinates of the
// GeometryNode (as the stroke is outside the geometry but inside the
// GeometryNode the geometry is translated by the stroke offset)
assertEquals(new Rectangle(3, 3, 30, 40), geometricOutline);
// translating it into parent coordinates should provide the same values
// as in the Shape case, i.e. the relocate values including the stroke
// offset
assertEquals(new Rectangle(33, 43, 30, 40), NodeUtils.localToParent(geometryNode, geometricOutline).getBounds());
}
@Test
public void getShapeOutline() {
// GeometryNode
GeometryNode<Rectangle> n = new GeometryNode<>();
n.setFill(Color.RED);
n.setStrokeWidth(5);
n.setStrokeType(StrokeType.OUTSIDE);
n.setGeometry(new Rectangle(30, 40, 30, 40));
n.relocate(30, 40);
IGeometry geometricOutline = NodeUtils.getShapeOutline(n);
assertTrue(geometricOutline instanceof Rectangle);
assertEquals(new Rectangle(0, 0, 40, 50), geometricOutline);
}
@Override
protected javafx.scene.shape.Rectangle doCreateVisual() {
javafx.scene.shape.Rectangle visual = new javafx.scene.shape.Rectangle();
visual.setTranslateX(-DEFAULT_SIZE / 2);
visual.setTranslateY(-DEFAULT_SIZE / 2);
visual.setFill(getMoveFill());
visual.setStroke(getStroke());
visual.setWidth(DEFAULT_SIZE);
visual.setHeight(DEFAULT_SIZE);
visual.setStrokeWidth(1);
visual.setStrokeType(StrokeType.OUTSIDE);
return visual;
}
@Override
protected GeometryNode<IGeometry> doCreateVisual() {
GeometryNode<IGeometry> visual = super.doCreateVisual();
visual.setStroke(Color.GREY);
visual.getStrokeDashArray().add(5.0);
visual.setStrokeLineJoin(StrokeLineJoin.BEVEL);
visual.setStrokeType(StrokeType.CENTERED);
return visual;
}
@Override
protected GeometryNode<IGeometry> doCreateVisual() {
GeometryNode<IGeometry> visual = new GeometryNode<>();
visual.setFill(Color.TRANSPARENT);
visual.setMouseTransparent(true);
visual.setManaged(false);
visual.setStrokeType(StrokeType.OUTSIDE);
visual.setStrokeWidth(1);
// hover specific
visual.setEffect(getHoverFeedbackEffect());
visual.setStroke(getHoverStroke());
return visual;
}