/* * Smart GWT (GWT for SmartClient) * Copyright 2008 and beyond, Isomorphic Software, Inc. * * Smart GWT is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3 * as published by the Free Software Foundation. Smart GWT is also * available under typical commercial license terms - see * http://smartclient.com/license * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import com.smartgwt.client.types.Cursor; import com.smartgwt.client.types.LineCap; import com.smartgwt.client.types.LinePattern; import com.smartgwt.client.widgets.Canvas; import com.smartgwt.client.widgets.Label; import com.smartgwt.client.widgets.drawing.DrawCurve; import com.smartgwt.client.widgets.drawing.DrawItem; import com.smartgwt.client.widgets.drawing.DrawLabel; import com.smartgwt.client.widgets.drawing.DrawLine; import com.smartgwt.client.widgets.drawing.DrawOval; import com.smartgwt.client.widgets.drawing.DrawPane; import com.smartgwt.client.widgets.drawing.DrawTriangle; import com.smartgwt.client.widgets.drawing.Point; import com.smartgwt.client.widgets.events.ClickEvent; import com.smartgwt.client.widgets.events.ClickHandler; import com.smartgwt.client.widgets.form.DynamicForm; import com.smartgwt.client.widgets.form.fields.ToggleItem; import com.smartgwt.client.widgets.form.fields.events.ChangedEvent; import com.smartgwt.client.widgets.form.fields.events.ChangedHandler; import com.smartgwt.client.widgets.layout.VStack; import com.google.gwt.core.client.EntryPoint; public class SvgHitDetectionSample implements EntryPoint { // Center point coordinates private final int centerX = 300; private final int centerY = 250; // Instance variables for shapes and UI private DrawItem[] allShapes; private Map
shapeNames; private Map
originalColors; private Map
originalWidths; private boolean usePreciseDetection = true; private DrawLine scanLine; private Label statusLabel; private DrawPane mainPane; public void onModuleLoad() { // Map to store custom shape names (since DrawItem doesn't have shapeName property) shapeNames = new HashMap
(); originalColors = new HashMap
(); originalWidths = new HashMap
(); mainPane = new DrawPane(); mainPane.setID("mainPane"); mainPane.setWidth(600); mainPane.setHeight(500); mainPane.setShowEdges(true); mainPane.setCursor(Cursor.CROSSHAIR); mainPane.setCanHover(true); mainPane.setPrompt("Click somewhere to see intersections"); // Large arc - opens downward DrawCurve arc1 = new DrawCurve(); arc1.setDrawPane(mainPane); arc1.setStartPoint(new Point(80, 350)); arc1.setEndPoint(new Point(200, 350)); arc1.setControlPoint1(new Point(80, 480)); arc1.setControlPoint2(new Point(200, 480)); arc1.setLineColor("#3498DB"); arc1.setLineWidth(6); arc1.setLineCap(LineCap.ROUND); registerShape(arc1, "Blue Arc"); arc1.draw(); // Arc on the right side DrawCurve arc2 = new DrawCurve(); arc2.setDrawPane(mainPane); arc2.setStartPoint(new Point(550, 100)); arc2.setEndPoint(new Point(450, 250)); arc2.setControlPoint1(new Point(450, 100)); arc2.setControlPoint2(new Point(450, 175)); arc2.setLineColor("#27AE60"); arc2.setLineWidth(6); arc2.setLineCap(LineCap.ROUND); registerShape(arc2, "Green Arc"); arc2.draw(); // S-Curve DrawCurve sCurve = new DrawCurve(); sCurve.setDrawPane(mainPane); sCurve.setStartPoint(new Point(241, 30)); sCurve.setEndPoint(new Point(238, 252)); sCurve.setControlPoint1(new Point(136, 55)); sCurve.setControlPoint2(new Point(234, 194)); sCurve.setLineColor("#E74C3C"); sCurve.setLineWidth(6); sCurve.setLineCap(LineCap.ROUND); registerShape(sCurve, "Red Curve"); sCurve.draw(); // Oval DrawOval oval1 = new DrawOval(); oval1.setDrawPane(mainPane); oval1.setLeft(420); oval1.setTop(320); oval1.setWidth(140); oval1.setHeight(80); oval1.setLineColor("#8E44AD"); oval1.setLineWidth(4); registerShape(oval1, "Purple Oval"); oval1.draw(); // Triangle DrawTriangle triangle1 = new DrawTriangle(); triangle1.setDrawPane(mainPane); triangle1.setPoints(new Point(50, 280), new Point(150, 280), new Point(100, 180)); triangle1.setLineColor("#E67E22"); triangle1.setLineWidth(4); registerShape(triangle1, "Orange Triangle"); triangle1.draw(); // Cyan curve at bottom DrawCurve arc3 = new DrawCurve(); arc3.setDrawPane(mainPane); arc3.setStartPoint(new Point(350, 450)); arc3.setEndPoint(new Point(550, 450)); arc3.setControlPoint1(new Point(400, 350)); arc3.setControlPoint2(new Point(500, 350)); arc3.setLineColor("#00BFFF"); arc3.setLineWidth(6); arc3.setLineCap(LineCap.ROUND); registerShape(arc3, "Cyan Curve"); arc3.draw(); allShapes = new DrawItem[] { arc1, arc2, sCurve, oval1, triangle1, arc3 }; // Center point marker DrawOval centerMarker = new DrawOval(); centerMarker.setDrawPane(mainPane); centerMarker.setLeft(centerX - 10); centerMarker.setTop(centerY - 10); centerMarker.setWidth(20); centerMarker.setHeight(20); centerMarker.setFillColor("#000000"); centerMarker.setLineColor("#FFFFFF"); centerMarker.setLineWidth(3); centerMarker.draw(); // Center label DrawLabel centerLabel = new DrawLabel(); centerLabel.setDrawPane(mainPane); centerLabel.setLeft(centerX + 18); centerLabel.setTop(centerY - 8); centerLabel.setContents("Center"); centerLabel.setFontSize(12); centerLabel.setFontWeight("bold"); centerLabel.setLineColor("#000000"); centerLabel.draw(); // Scan line from center to click point scanLine = new DrawLine(); scanLine.setDrawPane(mainPane); scanLine.setStartPoint(new Point(centerX, centerY)); scanLine.setEndPoint(new Point(centerX, centerY)); scanLine.setLineColor("#FF00FF"); scanLine.setLineWidth(3); scanLine.setLinePattern(LinePattern.DASH); scanLine.draw(); // Handle clicks on the pane mainPane.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { int x = mainPane.getOffsetX(); int y = mainPane.getOffsetY(); // Disable the one-time hover hint after first click if (mainPane.getPrompt() != null) { mainPane.setPrompt(null); } // Update the scan line and detect intersections scanLine.setEndPoint(new Point(x, y)); detectIntersections(x, y); } }); // Status label statusLabel = new Label(); statusLabel.setWidth(600); statusLabel.setHeight(30); statusLabel.setContents("
Line intersects:
(click anywhere to draw a line from center)"); statusLabel.setPadding(5); // Toggle for precise hit detection final ToggleItem toggleItem = new ToggleItem("preciseHitDetection", "Use precise geometric hit detection"); toggleItem.setWrapTitle(false); toggleItem.setDefaultValue(true); toggleItem.addChangedHandler(new ChangedHandler() { @Override public void onChanged(ChangedEvent event) { usePreciseDetection = (Boolean) event.getValue(); // Re-run detection with existing line position Point endPoint = scanLine.getEndPoint(); if (endPoint.getX() != centerX || endPoint.getY() != centerY) { detectIntersections(endPoint.getX(), endPoint.getY()); } else { resetShapes(); } } }); DynamicForm toggleForm = new DynamicForm(); toggleForm.setID("hitDetectionToggleForm"); toggleForm.setWidth(400); toggleForm.setItems(toggleItem); VStack layout = new VStack(); layout.setWidth100(); layout.setMembersMargin(10); layout.setMembers(statusLabel, mainPane, toggleForm); layout.draw(); } private void registerShape(DrawItem shape, String name) { String id = shape.getID(); shapeNames.put(id, name); originalColors.put(id, shape.getLineColor()); originalWidths.put(id, shape.getLineWidth()); } private String getShapeName(DrawItem shape) { return shapeNames.get(shape.getID()); } private void resetShapes() { for (DrawItem shape : allShapes) { String id = shape.getID(); shape.setLineColor(originalColors.get(id)); shape.setLineWidth(originalWidths.get(id)); } } private boolean isPointInBounds(DrawItem shape, int x, int y) { return shape.isInBounds(x, y); } private void detectIntersections(int endX, int endY) { resetShapes(); // Temporarily hide the scanLine so it doesn't block hit detection scanLine.hide(); Map
hitShapes = new LinkedHashMap
(); int numSamples = 100; for (int i = 0; i <= numSamples; i++) { double t = (double) i / numSamples; int localX = (int) (centerX + t * (endX - centerX)); int localY = (int) (centerY + t * (endY - centerY)); for (DrawItem shape : allShapes) { String name = getShapeName(shape); if (hitShapes.containsKey(name)) continue; boolean hit; if (usePreciseDetection) { hit = shape.isPointInPath(localX, localY); } else { hit = isPointInBounds(shape, localX, localY); } if (hit) { hitShapes.put(name, shape); } } } // Show the scanLine again scanLine.show(); // Highlight hit shapes StringBuilder hitNames = new StringBuilder(); for (Map.Entry
entry : hitShapes.entrySet()) { DrawItem shape = entry.getValue(); shape.setLineColor("#FFFF00"); shape.setLineWidth(10); if (hitNames.length() > 0) hitNames.append(", "); hitNames.append(entry.getKey()); } // Update status if (hitNames.length() > 0) { statusLabel.setContents("
Line intersects:
" + hitNames.toString()); } else { statusLabel.setContents("
Line intersects:
(no shapes)"); } } }