Skip to content

Instantly share code, notes, and snippets.

@drzhbe
Created April 3, 2017 08:36
Show Gist options
  • Save drzhbe/a39487d0337c1504f26b952af35c0696 to your computer and use it in GitHub Desktop.
Save drzhbe/a39487d0337c1504f26b952af35c0696 to your computer and use it in GitHub Desktop.
view events on timeline
property bool collecting: false
property var bbbbb: {
if (!collecting) {
collecting = true;
collect(branchCardBody)
}
}
function newEvent(item, eventName) {
var globalCoord = item.mapToItem(null, 0, 0);
return {
// Из строки типа CardFooter_QMLTYPE_347(0x89dcc898) берем только первую частичку
item: item.toString().split("_")[0],
eventName: eventName,
y: item.y,
height: item.height,
globalY: globalCoord.y
};
}
property var events: []
function subscribe(item) {
if (item.hasOwnProperty("height"))
item.heightChanged.connect(function() { events.push(newEvent(item, "height")) });
if (item.hasOwnProperty("y"))
item.yChanged.connect(function() { events.push(newEvent(item, "y")) });
if (item.hasOwnProperty("ready"))
item.readyChanged.connect(function() { events.push(newEvent(item, "ready")) });
}
function collect(item) {
var components = Array.prototype.map.call(item.children, function(child) {
return child.toString().split("_")[0];
});
components.unshift(branchCardBody.toString().split("_")[0]);
subscribe(branchCardBody);
for (var i = 0; i < item.children.length; i++) {
subscribe(item.children[i]);
}
setTimeout(function() {
var reply = {
jsonrpc: "2.0",
method: "collectYEvents",
result: {
events: events,
components: components
}
};
server.log(reply)
console.log("## [qml] reply", reply)
}, 3000)
}
import QtQuick 2.6
import QtQuick.Window 2.2
import QtWebSockets 1.0
Window {
id: root
visible: true
width: 1400
height: 600
title: qsTr("Hello World")
property var events: []
property var components: []
property var componentViews: ({})
property var componentEvents: ({})
property var blankEvent: ({
item: "-",
eventName: "-",
y: "-",
height: "-",
globalY: "-"
})
onComponentsChanged: {
if (components.length) {
root.height = components.length * 100;
}
}
WebSocket {
url: "ws://localhost:12345"
active: true
onTextMessageReceived: {
var data = JSON.parse(message);
// server.log в qml сует все данные в поле event
if (data.event) {
data = data.event;
}
if (data.method
&& data.method === "collectYEvents") {
// TODO (salnikov): now we only use the first pack of events
if (!root.events.length) {
var events = data.result.events;
events.forEach(function(event) {
if (!componentEvents[event.item]) {
componentEvents[event.item] = [];
}
var componentEventsIndex = componentEvents[event.item].push(event);
event.componentEventsIndex = componentEventsIndex;
});
componentEventsChanged();
root.events = events;
root.components = data.result.components;
}
}
}
onStatusChanged: {
switch (status) {
case WebSocket.Error:
console.error("Error: " + errorString);
break;
case WebSocket.Open:
console.log('## Hello bro');
break;
case WebSocket.Closed:
console.log('## Hello');
break;
}
}
}
Rectangle {
anchors.fill: parent
Text {
visible: events.length === 0
anchors.centerIn: parent
text: "Waiting for server.log..."
}
// Titles of components: first column
ListView {
anchors.fill: parent
model: components
delegate: Rectangle {
property bool ready
property int currentOwnEventIndex: -1
property var ownEvents: componentEvents[modelData] || []
id: componentNameView
width: 100
height: 100
color: ready ? "#33990000" : "white"
border.width: 1
border.color: "#999"
Component.onCompleted: {
componentViews[modelData] = componentNameView;
}
onCurrentOwnEventIndexChanged: {
if (!ownEvents) return;
if (currentOwnEventIndex < -1) {
currentOwnEventIndex = -1;
return;
} else if (currentOwnEventIndex >= ownEvents.length) {
currentOwnEventIndex = ownEvents.length - 1;
return;
}
var currentEvent = currentOwnEventIndex < 0
|| currentOwnEventIndex >= ownEvents.length
? blankEvent
: ownEvents[currentOwnEventIndex];
eventName.text = "e: " + currentEvent.eventName;
yVal.text = "y: " + currentEvent.y;
hVal.text = "h: " + currentEvent.height;
gyVal.text = "gY: " + currentEvent.globalY;
}
Column {
anchors.fill: parent
Text {
text: modelData
}
Text {
id: eventName
text: "e: -"
}
Text {
id: yVal
text: "y: -"
}
Text {
id: hVal
text: "h: -"
}
Text {
id: gyVal
text: "gY: -"
}
Text {
id: currentOwnEventIndexText
text: "i: " + (currentOwnEventIndex+1) + " / " + ownEvents.length
}
}
}
}
// Horizontal timeline with events
ListView {
id: timeline
anchors.fill: parent
anchors.leftMargin: 100
orientation: ListView.Horizontal
model: events
property real lastContentX: 0
signal newContentX(real oldContentX, real newContentX)
onContentXChanged: {
newContentX(lastContentX, contentX);
lastContentX = contentX;
}
delegate: Rectangle {
id: event
property bool entered: false
readonly property bool isReadyEvent: modelData.eventName === "ready"
property var componentView: componentViews[componentName]
property string componentName: modelData.item
y: root.components.indexOf(modelData.item) * 100
width: 100
height: 100
border.width: 1
border.color: "#999"
color: {
switch (modelData.eventName) {
case "y": return "#11009900";
case "height": return "#11000099";
case "ready": return "#11990000";
default: return "#33999999";
}
}
function isEntered(contentX) {
return timeline.contentX > event.width * index
&& timeline.contentX < event.width * (index + 1);
}
Connections {
target: timeline
onNewContentX: {
var nowEntered = isEntered(newContentX);
if (!entered && nowEntered) {
entered = true;
} else if (entered && !nowEntered) {
entered = false;
var componentView = componentViews[componentName];
if (!componentView) return;
var goingBackInTime = oldContentX > newContentX;
if (goingBackInTime) {
componentView.currentOwnEventIndex--;
if (isReadyEvent && componentView.ready) {
componentView.ready = false;
}
} else {
componentView.currentOwnEventIndex++;
if (isReadyEvent && !componentView.ready) {
componentView.ready = true;
}
}
}
}
}
Column {
anchors.fill: parent
Text {
color: "#555"
text: modelData.item
}
Text {
visible: modelData.eventName === "ready"
text: "e: " + modelData.eventName
}
Text {
visible: modelData.eventName === "y"
text: "y: " + modelData.y
}
Text {
visible: modelData.eventName === "height"
text: "h: " + modelData.height
}
// Text {
// visible: modelData.eventName === "y"
// text: "gY: " + modelData.globalY
// }
Text {
id: diffText
property real diff: {
var prevIndex = modelData.componentEventsIndex - 2;
if (prevIndex < 0) return 0;
var events = componentEvents[modelData.item];
var prevEvent = events[prevIndex];
console.log('## y', modelData.y, prevEvent.y);
switch (modelData.eventName) {
case "y":
return modelData.y - prevEvent.y;
case "height":
return modelData.height - prevEvent.height;
}
return 0;
}
onDiffChanged: console.log('## diff', diff);
visible: diff > 0
color: diff > 0 ? "#090" : "#900"
text: {
// 2 space margin at start
" " + (diff > 0 ? "+" : "") + diff
}
}
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment