Why does binding not work in JS code (QML)? - javascript

There's a kind of reusable element that have the property of Rectangle type:
property Item middleRegion: Rectangle {
color: "grey";
border.width: 1;
height: line.height;
parent: line
}
Then, if an user defines own middleRegion, onMiddleRegionChanged() is called:
onMiddleRegionChanged: {
middleRegion.parent = line
middleRegion.height = line.height
}
But, despite of the fact that line.height is changed, middleRegion.height isn't changed after it. Why does binding not work in this code?
The important thing that if user doesn't defined middleRegion, everything's going well.

I've found the answer by myself.
According to the example from Qt documentation the problem is solved by using Qt.binding():
import QtQuick 2.0
Rectangle {
width: 100
height: width * 2
focus: true
Keys.onSpacePressed: {
height = Qt.binding(function() { return width * 3 })
}
}

Related

Assign properties to possible components that can be defined inside a QML component

As a newbie to qml/qt programming, I would like to solve following issue;
MyComponent1.qml:
import QtQuick 2.0
Rectangle {
width: 100
height: 100
border.color: "black"
border.width: 5
Text {
height: 20
anchors.bottom: parent.bottom
}
}
MyComponent2.qml
import QtQuick 2.0
Rectangle {
MyComponent1{
//here can be added any kind of component Rectangle or other components
Rectangle {
anchors.top: parent.top
}
}
MyComponent1{
//here can be added any kind of component Rectangle or other components
Rectangle {
anchors.top: parent.top
}
}
MyComponent1{
//here can be added any kind of component Rectangle or other components
Rectangle {
anchors.top: parent.top
}
}
}
I want to achieve that Rectangle Component which is written under of comment lines in MyComponent2.qml have some properties which will be predefined (like anchors.top: parent.top) in MyComponent1.qml.
For this example:
"anchors.top: parent.top" is written 3 times within code in MyComponent2.qml.
Can we define it one time in MyComponent1.qml and apply it to all of 3 predefined Rectangle Components in MyComponent2.qml?
My goal is to increase the reusability of the code.
Thank you all in advance.
Use this property alias inside MyComponent1:
myRect : rectId
And use this inside MyComponent2 to redefine anchors of rectangle:
myRect.anchors.top : parent.top

Passing dynamic styles to my element in VueJS

I am trying to make a type of progress bar to track a percentage of tasks completed. I want to v-bind:styles and pass it {width: dynamicWidth + '%'} in order to control the progression of this bar. So far I have created a computed variable that will return the percentage complete I want to bar to display, and I have set up my dynamic style in the data object
export default{
data: function () {
return {
numQuotes: dataBus.numQuotes,
numberA: 30,
barWidth: {
width: this.barWidthCalculated +'%'
}
}
},
computed: {
barWidthCalculated: function(){
return this.numQuotes * 10;
}
}
}
I also added an element to the DOM to see what was happening.
<div id="trackerBar">
<div id="trackerBarActual" v-bind:style="barWidth">
<h2>{{numQuotes}}/10</h2>
<p>{{barWidthCalculated}}</p>
</div>
</div>
My bar stays fixed at 100%, i dont see any interpolation on the DOM. I also established another NUMBER variable in my data section and attempted to pass that to my width property, but still no change, and no rendering on the DOM. However if I pass any other elements in my styles object such as
color: 'red'
Those changes take place. Also if I pass my styles object a number directly ie...
barWidth: {
width: 50 +'%'
}
It displays correctly on the DOM.
What am I missing/doing wrong?
why not just use :
<div id="trackerBarActual" v-bind:style="barWidthCalculated">
computed: {
barWidthCalculated: function(){
return {
width: (this.numQuotes * 10) + '%',
color: 'red'
};
}

CodeMirror bad rendering on paste with custom css line-height

I'm using the latest version of CodeMirror (4.12). I set the style of .CodeMirror height:auto; and gave viewportMargin a value of Infinity (like Autoresize Demo).
Everything went fine until I decided to customize the line-height: if I set a few lines as the initial value or if I paste a large block of text, there's a margin at the bottom and the caret is not corresponding to the code. If I change the value by hitting a key or if I call cm.refresh();, it goes back to normal and will never create another bad rendering (until the page is reloaded).
The thing is, CodeMirror doesn't seem to provide an oncomplete or on-finish-rendering event. For now, the only way that I found is to add a few lines to the function setDocumentHeight(cm, measure) which seems to be the last function called when I paste something into an empty editor. Here's my code:
First, I created an object:
CodeMirror.prototype = {
editorPM :
{
firstSetValue : false,
firstPaste : false,
isPasting : false
},
...
Then I created a paste event
editor.getWrapperElement().addEventListener("paste", function(e)
{
editor.editorPM.isPasting = true;
});
Then I added a few lines to setDocumentHeight()
function setDocumentHeight(cm, measure) {
cm.display.sizer.style.minHeight = measure.docHeight + "px";
var total = measure.docHeight + cm.display.barHeight;
cm.display.heightForcer.style.top = total + "px";
cm.display.gutters.style.height =
Math.max(total + scrollGap(cm), measure.clientHeight) + "px";
var ePM = cm.editorPM;
if (!ePM.firstSetValue)
{
ePM.firstSetValue = true;
setTimeout(function(){
cm.refresh();
}, 300);
}
if (ePM.isPasting)
{
ePM.isPasting = false;
if (!ePM.firstPaste)
{
ePM.firstPaste = true;
setTimeout(function(){
cm.refresh();
}, 300);
}
}
}
So finally, I went back to a normal line-height because I hate having to put a timeout. Still, it would be very nice to have a solution to that problem. It seems like a bug to me! And I don't like the normal line-height to code, it's too tight.
Change the CSS of your line-height in the .CodeMirror class:
.CodeMirror {
/* Set height, width, borders, and global font properties here */
font-family: SourceCodePro, monospace, "Lucida Console";
font-weight: 200;
width: 100%;
height: auto;
line-height:3; // <---- Change Height Here
}

Is there any cross-browser javascript for making vh and vw units work

Note: Ok while I was typing this question I came across this
question which suggests to use #media query but was asked back in
2011...
As you know CSS3 introduces new Viewport-percentage length units, vh and vw, which I feel are really useful for a solid responsive layout, so my question is, is there any JavaScript/jQuery alternative for this? More over apart from using it for font sizes, is it safe to use for sizing elements? Like example
div {
height: 6vh;
width: 20vh; /* Note am using vh for both, do I need to use vw for width here? */
}
Update 5: .css(property) fix
Plugins like fancyBox use .css('margin-right') to fetch the right margin of an element and .css('margin-right', '12px') to set the right margin of an element. This was broken, because there was no check if props is a string and if there are multiple arguments given. Fixed it by checking if props is a string. If so and there is multiple arguments, arguments is rewritten into an object, otherwise parseProps( $.extend( {}, props ) ) is not used.
Update 4: Plugin for responsive layouts https://github.com/elclanrs/jquery.columns (in the works)
I gave this a (long) try. First here's the CSS example: http://jsbin.com/orajac/1/edit#css. (resize the output panel). Notice that the font-size doesn't work with viewport units, at least on latest Chrome.
And here's my attempt at doing this with jQuery. The jQuery demo which works with the font as well is at http://jsbin.com/izosuy/1/edit#javascript. Haven't tested it extensively but it seems to work with most properties since it's just converting the values to pixel and then by calling the plugin on window.resize it keeps updating.
Update: Updated code to work with many browsers. Test locally if you're using anything other than Chrome because jsBin acts a bit weird with window.resize.
Update 2: Extend native css method.
Update 3: Handle window.resize event inside of the plugin so the integration is now seamless.
The gist (to test locally): https://gist.github.com/4341016
/*
* CSS viewport units with jQuery
* http://www.w3.org/TR/css3-values/#viewport-relative-lengths
*/
;(function( $, window ){
var $win = $(window)
, _css = $.fn.css;
function viewportToPixel( val ) {
var percent = val.match(/[\d.]+/)[0] / 100
, unit = val.match(/[vwh]+/)[0];
return (unit == 'vh' ? $win.height() : $win.width()) * percent +'px';
}
function parseProps( props ) {
var p, prop;
for ( p in props ) {
prop = props[ p ];
if ( /[vwh]$/.test( prop ) ) {
props[ p ] = viewportToPixel( prop );
}
}
return props;
}
$.fn.css = function( props ) {
var self = this
, originalArguments = arguments
, update = function() {
if ( typeof props === 'string' || props instanceof String ) {
if (originalArguments.length > 1) {
var argumentsObject = {};
argumentsObject[originalArguments[0]] = originalArguments[1];
return _css.call(self, parseProps($.extend({}, argumentsObject)));
} else {
return _css.call( self, props );
}
} else {
return _css.call( self, parseProps( $.extend( {}, props ) ) );
}
};
$win.resize( update ).resize();
return update();
};
}( jQuery, window ));
// Usage:
$('div').css({
height: '50vh',
width: '50vw',
marginTop: '25vh',
marginLeft: '25vw',
fontSize: '10vw'
});
I am facing this issue with the Android 4.3 stock browser (doesn't support vw,vh, etc).
The way I solved this is using 'rem' as a font-size unit and dynamically changing the < html >'s font-size with javascript
function viewport() {
var e = window, a = 'inner';
if (!('innerWidth' in window )) {
a = 'client';
e = document.documentElement || document.body;
}
return { width : e[ a+'Width' ] , height : e[ a+'Height' ] };
}
jQuery(window).resize(function(){
var vw = (viewport().width/100);
jQuery('html').css({
'font-size' : vw + 'px'
});
});
and in your css you can use 'rem' instead of px,ems,etc
.element {
font-size: 2.5rem; /* this is equivalent to 2.5vw */
}
Here's a demo of the code : http://jsfiddle.net/4ut3e/
I wrote small helper to deal with this problem. It's supported on all main browsers and uses jQuery.
Here it is:
SupportVhVw.js
function SupportVhVw() {
this.setVh = function(name, vh) {
jQuery(window).resize( function(event) {
scaleVh(name, vh);
});
scaleVh(name, vh);
}
this.setVw = function(name, vw) {
jQuery(window).resize( function(event) {
scaleVw(name, vw);
});
scaleVw(name, vw);
}
var scaleVw = function(name, vw) {
var scrWidth = jQuery(document).width();
var px = (scrWidth * vw) / 100;
var fontSize = jQuery(name).css('font-size', px + "px");
}
var scaleVh = function(name, vh) {
var scrHeight = jQuery(document).height();
var px = (scrHeight * vh) / 100;
var fontSize = jQuery(name).css('font-size', px + "px");
}
};
Simple example how to use it in HTML:
<head>
<title>Example</title>
<!-- Import all libraries -->
<script type="text/javascript" src="js/libs/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/libs/SupportVhVw.js"></script>
</head>
<body>
<div id="textOne">Example text one (vh5)</div>
<div id="textTwo">Example text two (vw3)</div>
<div id="textThree" class="textMain">Example text three (vh4)</div>
<div id="textFour" class="textMain">Example text four (vh4)</div>
<script type="text/javascript">
// Init object
var supportVhVw = new SupportVhVw();
// Scale all texts
supportVhVw.setVh("#textOne", 5);
supportVhVw.setVw("#textTwo", 3);
supportVhVw.setVh(".textMain", 4);
</script>
</body>
It's available on GitHub:
https://github.com/kgadzinowski/Support-Css-Vh-Vw
Example on JSFiddle:
http://jsfiddle.net/5MMWJ/2/
Vminpoly is the only polyfill I know of — it's under develpment but works as of this post. There are static polyfills as part of the Jquery Columns and -prefix-free projects as well.
I've just made a very ugly, but perfectly working workaround for this WITH PURE CSS (no JS needed).
I came across a CSS stylesheet full of 'vw' declarations (also for heights and top/bottom properties) that needed to be rewritten for native Android Browser (which in versions 4.3 and below does NOT support 'vw' units).
Instead of rewriting everything to percentages, that are relative to parent's width (so the deeper in DOM, the most complicated calculations), which would give me a headache even before I would reach the first { height: Xvw } declaration, I generated myself the following stylesheet:
http://splendige.pl/vw2rem.css
I guess you're all familiar with 'em' units (if not: http://www.w3schools.com/cssref/css_units.asp). After some testing I discovered that old Android Browsers (as well as all the others) perfectly support the 'rem' units, which work the same as 'em', but are relative to the ROOT element font-size declaration (in most cases, the html tag).
So the easiest way to make this work was to declare the font-size for html tag that is equal to 1% of the viewport's width, e.g. 19.2px for 1920px viewport and use a lot of media queries for the whole 1920-320px range. This way I made the 'rem' unit equal to 'vw' in all resolutions (step is 10px, but you can even try declaring html{font-size} for every 1px). Then I just batch-replaced 'vw' with 'rem' and admired the working layout on Android 4.3 native browser.
Whatsmore, you can then redeclare the font-size even for the whole body tag (in whatever units you want: px, em, pt, etc.) and it does NOT affect the 'rem' equality to 'vw' in the whole stylesheet.
Hope this helps. I know it looks kinda silly, but works like a charm. Remember: if something looks stupid, but works, it is not stupid :)
"jquery.columns" is so far the best solutions.
https://github.com/elclanrs/jquery.columns
You only need 2 lines of codes to turn "vh" into a "all-browser scale".
Declare a class in html:
<img src="example.jpg" class="width50vh" />
Then in javascript:
$('.width50vh').css({width: '50vw'});
The simplest and most elegant solution I have found is to simply make a div that has height: 1vh; and width: 1vw; and when the page loads grab those values as pixels with getBoundingClientRect(). then add a listener to the document to listen for screen resizing and update the size when screen is resized.
I save the value in pixels of the vh and vw and then whenever I need to use vh i would just say 100 * vh which would give me 100vh.
Here is a code snippet on it's implementation, my answer is in vanilla js, no need for jquery.
function getViewportUnits(){
const placeholder = document.getElementById("placeholder");
const vh = placeholder.getBoundingClientRect().height;
const vw = placeholder.getBoundingClientRect().width;
console.log({vh: vh, vw: vw});
}
#placeholder{
background: red;
height: 1vh;
width: 1vw;
}
<body onload="getViewportUnits()">
<div id="placeholder"></div>
I've published a tiny lib that eases viewport-relative dimensions usage. Keep in mind it's not a polyfill, so it requires that you apply classes on the elements you want to resize. For instance, <div class="vh10 vw30">hello</div> will fill 10% of the height and 30% of the width.
Check it out: https://github.com/joaocunha/v-unit

How to update the source of an Image

I'm using the Raphaël Javascript lib (awesome stuff for SVG rendering, by the way) and am currently trying to update the source of an image as the mouse goes over it.
The thing is I can't find anything about it (it's probably not even possible, considering I've read a huge part of the Raphaël's source without finding anything related to that).
Does someone knows a way to do this ?
Maybe it can be done without directly using the Raphaël's API, but as the generated DOM elements doesn't have IDs I don't know how to manually change their properties.
I'm actually doing CoffeeScript, but it's really easy to understand. CoffeeScript is Javascript after all.
This is what I'm doing right know, and I would like the MouseOver and MouseOut methods to change the source of the "bg" attribute.
class Avatar
constructor: (father, pic, posx, posy) ->
#bg = father.container.image "pics/avatar-bg.png", posx, posy, 112, 112
#avatar = father.container.image pic, posx + 10, posy + 10, 92, 92
mouseOver = => #MouseOver()
mouseOut = => #MouseOut()
#bg.mouseover mouseOver
#bg.mouseout mouseOut
MouseOver: ->
#bg.src = "pics/avatar-bg-hovered.png"
alert "Hover"
MouseOut: ->
#bg.src = "pics/avatar-bg.png"
alert "Unhovered"
class Slider
constructor: ->
#container = Raphael "raphael", 320, 200
#sliderTab = new Array()
AddAvatar: (pic) ->
#sliderTab.push new Avatar this, pic, 10, 10
window.onload = ->
avatar = new Slider()
avatar.AddAvatar "pics/daAvatar.png"
This actually works, except for the "#bg.src" part : I wrote it knowing that it wouldn't work, but well...
var paper = Raphael("placeholder", 800, 600);
var c = paper.image("apple.png", 100, 100, 600, 400);
c.node.href.baseVal = "cherry.png"
I hope, you get the idea.
This works for me (and across all browsers):
targetImg.attr({src: "http://newlocation/image.png"})
I was using rmflow's answer until I started testing in IE8 and below which returned undefined for image.node.href.baseVal. IE8 and below did see image.node.src though so I wrote functions getImgSrc, setImgSrc so I can target all browsers.
function getImgSrc(targetImg) {
if (targetImg.node.src) {
return targetImg.node.src;
} else {
return targetImg.node.href.baseVal;
}
}
function setImgSrc(targetImg, newSrc) {
if (targetImg.node.src) {
targetImg.node.src = newSrc;
} else {
targetImg.node.href.baseVal = newSrc;
}
}

Categories