z3dd
z3dd

Reputation: 176

Adding rubberband zoom to ChartView via MouseArea

I have a ChartView item declared in QML and I need a rubberband-like zoom functionality. This can be achieved with semi-transparent rectangle and MouseArea item. The problem is with one rectangle it's only possible to select area from top-left to bottom-right due to the fact that Rectangle item with negative dim-s is either invisible or disabled. Although it's possible to apply transform to Rectangle

transform: Scale { origin.x: 0; origin.y: 0; xScale: -1}

I failed to find how to manipulate xScale/yScale properties from the outside.

Right now I draw 4 rectangles, one per each quadrant, with correct xScale/yScale and dims (code in the end).

So I wonder is there more elegant/easy solution to the problem?

ChartView {
    id: chartViewTop
    ...

    Rectangle{
        id: rubberBandRec1
        border.color: "black"
        border.width: 1
        opacity: 0.3
        visible: false
        transform: Scale { origin.x: 0; origin.y: 0; yScale: -1}
    }

    Rectangle{
        id: rubberBandRec2
        border.color: "black"
        border.width: 1
        opacity: 0.3
        visible: false
        transform: Scale { origin.x: 0; origin.y: 0; yScale: -1; xScale: -1}
    }

    Rectangle{
        id: rubberBandRec3
        border.color: "black"
        border.width: 1
        opacity: 0.3
        visible: false
        transform: Scale { origin.x: 0; origin.y: 0; xScale: -1}
    }

    Rectangle{
        id: rubberBandRec4
        border.color: "black"
        border.width: 1
        opacity: 0.3
        visible: false
    }

    MouseArea {
        anchors.fill: parent
        hoverEnabled: true
        onPressed: {
            rubberBandRec1.x = mouseX; rubberBandRec1.y = mouseY; rubberBandRec1.visible = true;
            rubberBandRec2.x = mouseX; rubberBandRec2.y = mouseY; rubberBandRec2.visible = true;
            rubberBandRec3.x = mouseX; rubberBandRec3.y = mouseY; rubberBandRec3.visible = true;
            rubberBandRec4.x = mouseX; rubberBandRec4.y = mouseY; rubberBandRec4.visible = true;
        }
        onMouseXChanged: {
            rubberBandRec1.width = mouseX - rubberBandRec1.x;
            rubberBandRec2.width = rubberBandRec2.x-mouseX;
            rubberBandRec3.width = rubberBandRec3.x-mouseX;
            rubberBandRec4.width = mouseX - rubberBandRec4.x;
        }
        onMouseYChanged: {
            rubberBandRec1.height = rubberBandRec1.y - mouseY;
            rubberBandRec2.height = rubberBandRec2.y - mouseY;
            rubberBandRec3.height = mouseY - rubberBandRec3.y;
            rubberBandRec4.height = mouseY - rubberBandRec4.y;
        }
        onReleased: {
            var x = rubberBandRec4.x-(rubberBandRec4.width<0)*Math.abs(rubberBandRec4.width);
            var y = rubberBandRec4.y-(rubberBandRec4.height<0)*Math.abs(rubberBandRec4.height);

            if (Math.abs(rubberBandRec4.width*rubberBandRec4.height)>100)
                chartViewTop.zoomIn(Qt.rect(x, y, Math.abs(rubberBandRec4.width),
                                            Math.abs(rubberBandRec4.height)));
            rubberBandRec1.visible = false;
            rubberBandRec2.visible = false;
            rubberBandRec3.visible = false;
            rubberBandRec4.visible = false;
        }
    }
}

Upvotes: 2

Views: 1781

Answers (1)

Todd Hay
Todd Hay

Reputation: 76

Set external properties for the scaling, and then just change these in the onMouseXChanged and onMouseYChanged events as follows. This appears to be working for me:

property int xScaleZoom: 0
property int yScaleZoom: 0

Rectangle{
    id: recZoom
    border.color: "steelblue"
    border.width: 1
    color: "steelblue"
    opacity: 0.3
    visible: false
    transform: Scale { origin.x: 0; origin.y: 0; xScale: xScaleZoom; yScale: yScaleZoom}
}
MouseArea {
    anchors.fill: parent
    hoverEnabled: true
    onPressed: {
        recZoom.x = mouseX;
        recZoom.y = mouseY;
        recZoom.visible = true;
    }
    onMouseXChanged: {
        if (mouseX - recZoom.x >= 0) {
            xScaleZoom = 1;
            recZoom.width = mouseX - recZoom.x;
        } else {
            xScaleZoom = -1;
            recZoom.width = recZoom.x - mouseX;
        }
    }
    onMouseYChanged: {
        if (mouseY - recZoom.y >= 0) {
            yScaleZoom = 1;
            recZoom.height = mouseY - recZoom.y;
        } else {
            yScaleZoom = -1;
            recZoom.height = recZoom.y - mouseY;
        }
    }
    onReleased: {
        var x = (mouseX >= recZoom.x) ? recZoom.x : mouseX
        var y = (mouseY >= recZoom.y) ? recZoom.y : mouseY
        chartView.zoomIn(Qt.rect(x, y, recZoom.width, recZoom.height));
        recZoom.visible = false;
    }
}

Upvotes: 6

Related Questions