Directory

← Back

Svg Component

Allows the creation of SVG elements from the server side

Author

Contributors

Rating

Overview

The Vaadin Component Factory SVG component is a wrapper around svg.js that allows creation of simple and complex SVGs from the Vaadin server-side code.

Usage

Add the dependency to your project (see sidebar in directory). Create a new Svg component and add an SvgElement element into it (see code examples)

Client-side implementation

This is the server-side (Java) API for the Vaadin Platform for the vcf-svg component. Looking for the client-side version? It can be found here: https://vaadin.com/directory/component/vaadin-component-factoryvcf-svg

License & Author

This Add-on is distributed under Apache 2.0

Component Factory Svg is written by Vaadin Ltd.

Major pieces of development of this add-on has been sponsored by multiple customers of Vaadin. Read more about Expert on Demand at: Support and Pricing

Sample code

        Svg draw = new Svg();
        Rect rect = new Rect("rect", 100, 100);
        Circle circle = new Circle("circle", 50);

        rect.move(75, 0);
        rect.size(150, 150);

        circle.center(150, 75);
        circle.setRadius(75);
        circle.setFillColor("#396");

        draw.add(rect);
        draw.add(circle);
        VerticalLayout demoContainer = new VerticalLayout();
        HorizontalLayout controlButtons = new HorizontalLayout();
        demoContainer.add(controlButtons);
        Span dragDetail = new Span();
        demoContainer.add(dragDetail);

        Svg svg = new Svg();
        svg.viewbox(0, 0, 380, 380);
        svg.setWidth("100%");
        svg.setHeight("500px");

        double size = 100;
        double space = size + 20;
        double x = 20;
        double y = 20;
        String fillColor = "#ff0066";

        //Rect
        Rect rect = new Rect("rect1", size, size);
        rect.setFillColor(fillColor);
        rect.move(x, y);
        svg.add(rect);

        //Circle
        double circleRadial = size / 2;
        Circle circle = new Circle("circle1", circleRadial);
        circle.setFillColor(fillColor);
        circle.move(x += space, y);
        svg.add(circle);

        //Ellipse
        Ellipse ellipse =
            new Ellipse("ellipse1", circleRadial, circleRadial * 0.5);
        ellipse.setFillColor(fillColor);
        ellipse.move(x += space, y);
        svg.add(ellipse);

        //Line
        Line line = new Line("line",
            new AbstractPolyElement.PolyCoordinatePair(x = 20, y += space),
            new AbstractPolyElement.PolyCoordinatePair(x + size,
                y + size));
        line.setStroke(fillColor, 10, Path.LINE_CAP.ROUND, null);
        svg.add(line);

        //Polyline
        List<AbstractPolyElement.PolyCoordinatePair> points = new ArrayList<>();
        points.add(new Polyline.PolyCoordinatePair(50, 0));
        points.add(new Polyline.PolyCoordinatePair(60, 40));
        points.add(new Polyline.PolyCoordinatePair(100, 50));
        points.add(new Polyline.PolyCoordinatePair(60, 60));
        points.add(new Polyline.PolyCoordinatePair(50, 100));
        points.add(new Polyline.PolyCoordinatePair(40, 60));
        points.add(new Polyline.PolyCoordinatePair(0, 50));
        points.add(new Polyline.PolyCoordinatePair(40, 40));

        Polyline polyline = new Polyline("polyline", points);
        polyline.setFillColor("none");
        polyline.setStroke(fillColor, 4, Path.LINE_CAP.ROUND,
            Path.LINE_JOIN.ROUND);
        polyline.move(x += space, y);
        svg.add(polyline);

        //Polygon
        Polygon polygon = new Polygon("polygon", points);
        polygon.setFillColor(fillColor);
        polygon.move(x += space, y);
        svg.add(polygon);

        //Path
        Path path = new Path("path",
            "M0 0 H50 A20 20 0 1 0 100 50 v25 C50 125 0 85 0 85 z");
        path.setFillColor("none");
        path.setStroke(fillColor, 4, Path.LINE_CAP.ROUND,
            Path.LINE_JOIN.ROUND);
        path.move(x = 20, y += space);
        svg.add(path);

        //Text
        Text text = new Text("text", "Sample text.");
        text.setFontFamily("'Roboto', 'Noto', sans-serif");
        text.setFillColor(fillColor);
        text.move(x += space, y);
        svg.add(text);

        //Image
        Image image = new Image("image",
            "https://vaadin.com/images/hero-reindeer.svg");
        image.size(size, size);
        image.move(x += space, y);
        image.setDraggable(false);
        svg.add(image);

        demoContainer.add(svg);

        //Add control buttons
        controlButtons.add(new Button("Toggle Zoom", e -> {
            svg.setZoomEnabled(!svg.isZoomEnabled());
        }));

        controlButtons.add(new Button("Toggle draggable", e -> {
            svg.getSvgElements().forEach(el ->
                el.setDraggable(!el.isDraggable()));

            svg.getSvgElements().forEach(el -> {

                // Due to the nature of how the polygons are written (M0 0),
                // if we do an update to them they will move back to 0,0.
                // Hence, we have to move them back to their desired
                // location when we do an update.
                if (el == polyline) {
                    el.move(20 + space, 20 + space);
                }

                if (el == polygon) {
                    el.move(20 + space * 2, 20 + space);
                }

                svg.update(el);
            });
        }));

        controlButtons.add(new Button("Stroke black", e -> {
            svg.getSvgElements().forEach(el ->
                el.setStroke("#000000", 4, Path.LINE_CAP.ROUND,
                    Path.LINE_JOIN.ROUND));
            svg.getSvgElements().forEach(el -> {

                // Due to the nature of how the polygons are written (M0 0),
                // if we do an update to them they will move back to 0,0.
                // Hence, we have to move them back to their desired
                // location when we do an update.
                if (el == polyline) {
                    el.move(20 + space, 20 + space);
                }

                if (el == polygon) {
                    el.move(20 + space * 2, 20 + space);
                }

                svg.update(el);
            });
        }));
        controlButtons.add(new Button("Display drag events", e -> {
            svg.addDragStartListener(event -> {
                Notification.show("Drag start: " +
                        event.getElement().getId(),2500,
                    Notification.Position.MIDDLE);
                dragDetail.setText("Drag Start for: " +
                    event.getElement().getId() +
                    " X: " + event.getElementX() +
                    " Y: " + event.getElementY());
            });

            svg.addDragEndListener(event -> {
                Notification.show("Drag End: " +
                    event.getElement().getId(), 2500,
                    Notification.Position.MIDDLE);
                dragDetail.setText("Drag End for: " +
                    event.getElement().getId() +
                    " X: " + event.getElementX() +
                    " Y: " + event.getElementY());
            });

              svg.addDragMoveListener(event -> {
                  dragDetail.setText("Drag Move for: " +
                      event.getElement().getId() +
                      " X: " + event.getElementX() +
                      " Y: " + event.getElementY());
//            });

            e.getSource().setEnabled(false);
        }));

        controlButtons.add(new Button("Remove Line", e -> {
            svg.remove(line);
            e.getSource().setEnabled(false);
        }));
 //Extend the rectangle to add a missing or new attribute 
    public class MyCustomSvg extends Rect {

        public MyCustomSvg(String id, double width, double height) {
            super(id, width, height);
        }

        // Ensure that the client-side actually knows how to handle
        // the attribute or if you made your own extension that
        // the attribute names match.
        // For existing client-side attributes look to
        // https://svgjs.com/docs/3.0/manipulating/#attributes
        public void setMyCustomAttribute(){
            setAttribute("theAttributeToSet", "theValueToSet");
        }

        public String getMyCustomAttribute(){
            return getStringAttribute("theAttributeISet");
        }
    }
@Route("ex")
public class ExView extends VerticalLayout {
    
    public ExView() {
        MyCustomSvgComponentWithExtendedEventListenerParams svg =
            new MyCustomSvgComponentWithExtendedEventListenerParams();
        add(svg);

        Circle circle = new Circle("c1", 50);
        circle.setDraggable(true);
        svg.add(circle);

        svg.addDragEndListener(event -> {
            System.out.println("The width on drag end was: " +
                event.getRawEventData()
                    .getNumber(
                        "event.detail.handler.el.node.instance.width()"));
        });
    }

    public static class MyCustomSvgComponentWithExtendedEventListenerParams 
        extends Svg {

        private static final Logger log =Logger.getLogger(
            MyCustomSvgComponentWithExtendedEventListenerParams.class.getName());
        private DomListenerRegistration dragendDomRegistration;

        @Override
        protected void ensureDomDragEndEventListenerRegistered() {
            //super.ensureDomDragEndEventListenerRegistered();

            /*
             * Copied default implementation from super.
             */
            if (dragendDomRegistration == null) {
                dragendDomRegistration = 
                    getElement().addEventListener("dragend", e -> {
                    onDragEndEvent(e.getEventData()
                        .getString("event.detail.handler.el.node.id"), 
                        e.getEventData());
                }).addEventData("event.detail.handler.el.node.id")
                    .addEventData("event.detail.handler.el.node.instance.x()")
                    .addEventData("event.detail.handler.el.node.instance.y()");
                /*
                 *   End of copied default implementation from super
                 */

                //Say we want to include the width of the element when the drag ends
                dragendDomRegistration
                    .addEventData("event.detail.handler.el.node.instance.width()");
            }
        }
    }
}

Compatibility

(Loading compatibility data...)

Was this helpful? Need more help?
Leave a comment or a question below. You can also join the chat on Discord or ask questions on StackOverflow.

Version

Fix an error when the component was used in a dialog

Released
2021-09-01
Maturity
STABLE
License
Apache License 2.0

Compatibility

Framework
Vaadin 14+
Browser
Firefox
Safari
Google Chrome
Microsoft Edge
Online