550-visual-selector
dgtlmoon 3 years ago
parent eef98c6adc
commit ea4a8ed580

@ -1119,12 +1119,11 @@ def changedetection_app(config=None, datastore_o=None):
with sync_playwright() as p: with sync_playwright() as p:
browser = p.chromium.connect_over_cdp("ws://127.0.0.1:3000") browser = p.chromium.connect_over_cdp("ws://127.0.0.1:3000")
page = browser.new_page() page = browser.new_page()
page.set_viewport_size({"width": 1220, "height": 800})
page.goto(watch['url']) page.goto(watch['url'])
# time.sleep(3) #time.sleep(3)
# https://github.com/microsoft/playwright/issues/620 # https://github.com/microsoft/playwright/issues/620
screenshot = page.screenshot(type='jpeg', clip={'x': 1.0, 'y': 1.0, 'width': 1280, 'height': 1024})
screenshot = page.screenshot(type='jpeg', full_page=True) screenshot = page.screenshot(type='jpeg', full_page=True)
# Could be made a lot faster # Could be made a lot faster
# https://toruskit.com/blog/how-to-get-element-bounds-without-reflow/ # https://toruskit.com/blog/how-to-get-element-bounds-without-reflow/
@ -1141,13 +1140,13 @@ def changedetection_app(config=None, datastore_o=None):
var bbox; var bbox;
for (var i = 0; i < elements.length; i++) { for (var i = 0; i < elements.length; i++) {
bbox = elements[i].getBoundingClientRect(); bbox = elements[i].getBoundingClientRect();
if ( bbox['width'] == window.innerWidth ) {
if (! bbox['width'] || !bbox['height'] ) {
continue; continue;
} }
if (bbox['width'] >500 && bbox['height'] >500 ) { if (bbox['width'] <10 || bbox['height'] <10 ) {
continue; continue;
} }
if(! 'textContent' in elements[i] || elements[i].textContent.length < 2 ) { if(! 'textContent' in elements[i] || elements[i].textContent.length < 2 ) {
continue; continue;
} }

@ -0,0 +1,56 @@
/**
* debounce
* @param {integer} milliseconds This param indicates the number of milliseconds
* to wait after the last call before calling the original function.
* @param {object} What "this" refers to in the returned function.
* @return {function} This returns a function that when called will wait the
* indicated number of milliseconds after the last call before
* calling the original function.
*/
Function.prototype.debounce = function (milliseconds, context) {
var baseFunction = this,
timer = null,
wait = milliseconds;
return function () {
var self = context || this,
args = arguments;
function complete() {
baseFunction.apply(self, args);
timer = null;
}
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(complete, wait);
};
};
/**
* throttle
* @param {integer} milliseconds This param indicates the number of milliseconds
* to wait between calls before calling the original function.
* @param {object} What "this" refers to in the returned function.
* @return {function} This returns a function that when called will wait the
* indicated number of milliseconds between calls before
* calling the original function.
*/
Function.prototype.throttle = function (milliseconds, context) {
var baseFunction = this,
lastEventTimestamp = null,
limit = milliseconds;
return function () {
var self = context || this,
args = arguments,
now = Date.now();
if (!lastEventTimestamp || now - lastEventTimestamp >= limit) {
lastEventTimestamp = now;
baseFunction.apply(self, args);
}
};
};

@ -1,4 +1,6 @@
$("img#selector-background").bind('load', function () { var current_selected_i;
function fetch_data() {
// Image is ready // Image is ready
$('.fetching-update-notice').html("Fetching element data.."); $('.fetching-update-notice').html("Fetching element data..");
@ -9,62 +11,51 @@ $("img#selector-background").bind('load', function () {
$('.fetching-update-notice').html("Rendering.."); $('.fetching-update-notice').html("Rendering..");
reflow_selector(data); reflow_selector(data);
}); });
};
});
function reflow_selector(selector_data) { function reflow_selector(selector_data) {
$('#selector-canvas').attr('width', $("img#selector-background").width());
$('#selector-canvas').attr('height', $("img#selector-background").height());
//.attr('height', $("img#selector-background").height());
// could trim it according to the lowest/furtheret item in the dataset
stage = new createjs.Stage("selector-canvas");
// to get onMouseOver & onMouseOut events, we need to enable them on the
// stage:
stage.enableMouseOver();
output = new createjs.Text("Test press, click, doubleclick, mouseover, and mouseout", "14px Arial");
output.x = output.y = 10;
stage.addChild(output);
var squares = [];
for (var i = 0; i < selector_data.length; i++) {
squares[i] = new createjs.Shape();
squares[i].graphics.beginFill("rgba(215,0,0,0.2)").drawRect(
selector_data[i]['left'],
selector_data[i]['top'],
selector_data[i]['width'],
selector_data[i]['height']);
squares[i].name = selector_data[i]['xpath'];
stage.addChild(squares[i]);
squares[i].on("click", handleMouseEvent); // $('#selector-canvas').attr('width',
squares[i].on("dblclick", handleMouseEvent); // $("img#selector-background")[0].getBoundingClientRect().width);
squares[i].on("mouseover", handleMouseEvent); var c = document.getElementById("selector-canvas");
squares[i].on("mouseout", handleMouseEvent); var selector_image = document.getElementById("selector-background");
squares.push(squares[i]); var selector_image_rect = selector_image.getBoundingClientRect();
}
$('#selector-canvas').attr('height', selector_image_rect.height);
$('#selector-canvas').attr('width', selector_image_rect.width);
stage.update();
$('.fetching-update-notice').hide();
} var ctx = c.getContext("2d");
ctx.strokeStyle = 'rgba(255,0,0,5)';
function handleMouseEvent(evt) {
output.text = "evt.target: " + evt.target + ", evt.type: " + evt.type; // set this on resize too
var x_scale = selector_image_rect.width / selector_image.naturalWidth;
if(evt.type == 'mouseover') { var y_scale = selector_image_rect.height / selector_image.naturalHeight;
evt.target.graphics.beginFill("rgba(225,220,220,0.9)");
} console.log(selector_data.length + " selectors found");
$('#selector-canvas').bind('mousemove', function (e) {
if(evt.type == 'mouseout') { ctx.clearRect(0, 0, c.width, c.height);
evt.target.graphics.beginFill("rgba(1,1,1,0.4)"); current_selected_i=null;
}
// Reverse order - the most specific one should be deeper/"laster"
// to save CPU, we're only updating when we need to, instead of on a tick:1 for (var i = selector_data.length; i!=0; i--) {
stage.update(); // draw all of them? let them choose somehow?
var sel = selector_data[i-1];
if (e.offsetY > sel.top * y_scale && e.offsetY < sel.top * y_scale + sel.height * y_scale
&&
e.offsetX > sel.left * y_scale && e.offsetX < sel.left * y_scale + sel.width * y_scale
) {
ctx.strokeRect(sel.left * x_scale, sel.top * y_scale, sel.width * x_scale, sel.height * y_scale);
// no need to keep digging
current_selected_i=i;
break;
}
}
}.debounce(5));
$('#selector-canvas').bind('mousedown', function (e) {
alert(selector_data[current_selected_i].xpath);
});
} }

@ -450,7 +450,11 @@ ul {
position: relative; } position: relative; }
#selector-wrapper > img { #selector-wrapper > img {
position: absolute; position: absolute;
z-index: 4; } z-index: 4;
max-width: 100%; }
#selector-wrapper > canvas { #selector-wrapper > canvas {
position: absolute; position: relative;
z-index: 5; } z-index: 5;
max-width: 100%; }
#selector-wrapper > canvas:hover {
cursor: pointer; }

@ -637,14 +637,19 @@ ul {
#selector-wrapper { #selector-wrapper {
position: relative; position: relative;
//width: 100%;
> img { > img {
position: absolute; position: absolute;
z-index: 4; z-index: 4;
max-width: 100%;
} }
>canvas { >canvas {
position: absolute; position: relative;
z-index: 5; z-index: 5;
max-width: 100%;
&:hover {
cursor: pointer;
}
} }
} }

@ -12,7 +12,7 @@
</script> </script>
<script type="text/javascript" src="{{url_for('static_content', group='js', filename='notifications.js')}}" defer></script> <script type="text/javascript" src="{{url_for('static_content', group='js', filename='notifications.js')}}" defer></script>
<script type="text/javascript" src="{{url_for('static_content', group='js', filename='visual-selector.js')}}" defer></script> <script type="text/javascript" src="{{url_for('static_content', group='js', filename='visual-selector.js')}}" defer></script>
<script src="https://code.createjs.com/easeljs-0.8.2.min.js"></script> <script type="text/javascript" src="{{url_for('static_content', group='js', filename='limit.js')}}" defer></script>
<div class="edit-form monospaced-textarea"> <div class="edit-form monospaced-textarea">
@ -187,7 +187,13 @@ nav
<div id="selector-wrapper"> <div id="selector-wrapper">
<!-- request the screenshot and get the element offset info ready --> <!-- request the screenshot and get the element offset info ready -->
<!-- use img src ready load to know everything is ready to map out --> <!-- use img src ready load to know everything is ready to map out -->
<img id="selector-background" src="{{ url_for('visualselector_request_current_screenshot_and_metadata', uuid=uuid) }}"/> <img id="selector-background" />
<script>
$("img#selector-background").attr("src", "{{ url_for('visualselector_request_current_screenshot_and_metadata', uuid=uuid) }}");
$("img#selector-background").bind('load', function () {
fetch_data();
});
</script>
<canvas id="selector-canvas"></canvas> <canvas id="selector-canvas"></canvas>
</div> </div>
</div> </div>

Loading…
Cancel
Save