HanSolo / medusa

A JavaFX library for Gauges
Apache License 2.0
692 stars 131 forks source link

Display angle? #137

Closed piegamesde closed 7 years ago

piegamesde commented 7 years ago

I need to display an angle, but not with a needle, but with two needles enclosing that angle. Is this possible to do with this library? I also thought about overlaying two gauges but I wanted to ask if there are any official solutions first.

By the way: I googled my problem, found your blog article, plugged in the code and it worked marvelously. This is rare in the JavaFX world, so thanks for that! This library definitely needs more attention.

HanSolo commented 7 years ago

Well it is not possible at the moment but I can make it possible :) It would be very helpful to have a drawing, photo or screenshot of the gauge you are looking for. Could you provide something like that?

piegamesde commented 7 years ago

I want the user to input an angle for the field of view of a camera (<180°). Anything that represents this visually in a clear way and does not clash with my compass above it is fine. Here my compass for reference:

        Gauge gauge = GaugeBuilder.create()
                .minValue(0)
                .maxValue(359)
                .startAngle(180)
                .angleRange(360)
                .autoScale(false)
                .customTickLabelsEnabled(true)
                .customTickLabels("N", "", "", "", "", "", "", "", "",
                        "E", "", "", "", "", "", "", "", "",
                        "S", "", "", "", "", "", "", "", "",
                        "W", "", "", "", "", "", "", "", "")
                .customTickLabelFontSize(96)
                .minorTickMarksVisible(false)
                .mediumTickMarksVisible(false)
                .majorTickMarksVisible(false)
                .valueVisible(false)
                .needleType(NeedleType.BIG)
                .needleShape(NeedleShape.ANGLED)
                .knobType(KnobType.FLAT)
                .knobColor(Gauge.DARK_COLOR)
                .borderPaint(Gauge.DARK_COLOR)
                .animated(false)
                .animationDuration(0)
                .needleBehavior(NeedleBehavior.STANDARD)
                .build();
HanSolo commented 7 years ago

But should the field of view also point into a specific direction? So you might also think about using a section which you could show in the compass for example...

piegamesde commented 7 years ago

At the moment the compass shows the rotation of the camera and the field of view shows its horizontal view angle. But having both in one is absolutely a great idea I didn't think of previously. If not, I don't really care about the direction of the angle.

I'm not really far into the API with areas, sections and such but it is worth a try. Do sections use properties too or will I have to use listeners here?

Edit:

It works really well, thank you for the input! I couldn't really use the property bindings because a) the sections don't handle overdraw (position < 0° or position > 360°) and b) updating a section does not trigger an update event on the gauge (you need to add a listener that does it manually) so I needed some more sophisticated code to position them:

Color needleColor = Color.RED.deriveColor(0, 0.5, 1.5, 0.8);
Section sectionA = new Section(0, 0, needleColor);
gauge.addSection(sectionA);
Section sectionB = new Section(0, 0, needleColor);
gauge.addSection(sectionB);

Color areaColor = Color.DARKGRAY.deriveColor(0, 1, 1, 0.5);
Section areaA = new Section(0, 0, areaColor);
areaA.startProperty().bind(sectionA.startProperty());
areaA.stopProperty().bind(sectionA.stopProperty());
gauge.addArea(areaA);
Section areaB = new Section(0, 0, areaColor);
areaB.startProperty().bind(sectionB.startProperty());
areaB.stopProperty().bind(sectionB.stopProperty());
gauge.addArea(areaB);

needleColor = needleColor.deriveColor(0, 0.5, 0.5, 1);
Section areaStart = new Section(0, 0, needleColor);
gauge.addArea(areaStart);
Section areaStop = new Section(0, 0, needleColor);
gauge.addArea(areaStop);

final double areaCornerSize = 3;
InvalidationListener e = observable -> {
    double needlePos = rotation.valueProperty().get();
    double startPos = needlePos - fov.valueProperty().get() / 2;
    double stopPos = needlePos + fov.valueProperty().get() / 2;

    if (startPos < 0) {
        sectionB.setStart(startPos + 360);
        sectionB.setStop(360);
        sectionA.setStart(0);
        sectionA.setStop(stopPos);

        areaStart.setStart(startPos + 360);
        areaStart.setStop(startPos + 360 + areaCornerSize);
        areaStop.setStart(stopPos - areaCornerSize);
        areaStop.setStop(stopPos);
    } else if (stopPos > 360) {
        sectionA.setStart(startPos);
        sectionA.setStop(360);
        sectionB.setStart(0);
        sectionB.setStop(stopPos - 360);

        areaStart.setStart(startPos);
        areaStart.setStop(startPos + areaCornerSize);
        areaStop.setStart(stopPos - 360 - areaCornerSize);
        areaStop.setStop(stopPos - 360);
    } else {
        sectionA.setStart(startPos);
        sectionA.setStop(needlePos);
        sectionB.setStart(needlePos);
        sectionB.setStop(stopPos);

        areaStart.setStart(startPos);
        areaStart.setStop(startPos + areaCornerSize);
        areaStop.setStart(stopPos - areaCornerSize);
        areaStop.setStop(stopPos);
    }

    gauge.setValue(needlePos);
    gauge.fireUpdateEvent(new UpdateEvent(gauge, UpdateEvent.EventType.REDRAW));
};
rotation.valueProperty().addListener(e);
fov.valueProperty().addListener(e);
e.invalidated(null);

I got some problems with the size of the gauge, but after putting it in an AnchorPane everything went right. Here's the result:

image