D3 visibility - if statement - if-statement

I have a function, which changes the visibility of an element, by clicking a button.
$<button class="pure-button pure-button-primary" title="convex-button" onclick= "convexHullvisibility()"><i>Convex Hull</i></button>$
Unfortunately, this function does not work and I think the problem is in if statement.
function convexHullvisibility(){
if (hull.attr("visibility", "visible")){
alert("1");
hull.attr("visibility", "hidden");
}
else{
alert("2");
hull.attr("visibility", "visible");
}
}
The definition of hull is here
svg.append("rect")
.attr("width", width)
.attr("height", height);
var hull = svg.append("path")
.attr("class", "hull")
.attr("visibility", "visible");
var vertices = [];
function redraw() {
hull.datum(d3.geom.hull(vertices)).attr("d", function (d) {
return "M" + d.join("L") + "Z";
});
}
Any help with the if-statement??

The two-argument attr is used to set attribute values, if you want to test them you need to use the single-argument form to get the value and test it with normal JS operators
if (hull.attr("visibility") == "visible"){

Related

If any row in range (G11:G25) contains boolean (true) then run function, else msgBox

The function I'm running (clearRowContents) in sheet 'Section 2' will clear contents and validation for any checked item (col H) in a list as well as the checkbox itself (col G). The remaining unchecked boxes and list items will then be sorted to clear any blank rows just created by the clearRowContents function. This functions works as tested.
However, if no item is checked (col G == false) and the "clear" button is pressed, how can I have a message pop up letting the user know that they must first check the box next to the item and then press the button to clear its contents from the list? I'm trying to figure out how to write the script for the clearItemMessage function.
Also, for script writing purposes, this sheet will be duplicated many times to create various validation menus for different topics... each sheet will be a different "chapter" in a manual with its own unique set of drop downs (in a MASTER DROPDOWN tab).
link to sheet: https://docs.google.com/spreadsheets/d/1ZdlJdhA0ZJOIwLA9dw5-y5v1FyLfRSywjmQ543EwMFQ/edit?usp=sharing
code:
function clearItemMessage(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var checkboxRange = ss.getRangeList("$G$11:$G$25").getValues();
if (checkboxRange == true){
clearRowContents (col);
} else (Browser.msgBox("To delete items, select the box next to the items and then press the delete button."));
}
function clearRowContents (col){ // col is the index of the column to check for checkbox being true
var col = 7; //col G
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var data = ss.getDataRange().getValues();
//Format font & size
var sheetFont = ss.getRange("A:Z");
var boxFont = ss.getRange("$G$11:$G$25");
var listFont = ss.getRange("$H$11:$H$25");
sheetFont.setFontFamily("Montserrat");
boxFont.setFontSize(8)
.setFontColor("#434343")
.setBackground("#ffffff");
listFont.setFontSize(12)
.setFontColor("#434343")
.setBackground("#ffffff");
//clear 'true' data validations
var deleteRanges = data.reduce(function(ar, e, i) {
if (e[col - 1] === true) {
return ar.concat(["H" + (i + 1), "G" + (i + 1)]);
}
return ar;
}, []);
if (deleteRanges.length > 0) {
ss.getRangeList(deleteRanges).clearContent().clearDataValidations();
}
//sort based on checkbox value
var range = ss.getRange("$G$11:$H$25");
range.sort({column: 7, ascending: false});
}
In your situation, how about modifying clearItemMessage() as follows?
Modified script:
function clearItemMessage(){
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var checkboxes = ss.getRange("$G$11:$G$25").getValues();
if (checkboxes.filter(([g]) => g === true).length > 0){ // or if (checkboxes.some(([g]) => g === true)) {
clearRowContents();
} else {
Browser.msgBox("To delete items, select the box next to the items and then press the delete button.");
}
}
From your question, I understood your clearRowContents works. So I proposed to modify clearItemMessage.
In your clearRowContents, var col = 7 is used. So I think that function clearRowContents (col){ can be modified to function clearRowContents (){.
Reference:
filter()

After Effects Expression (if layer is a CompItem)

I am trying to make slight modification at line 5 of below After Effects expression. Line 5 checks if the layer is visible and active but I have tried to add an extra check that the layer should not be a comp item. (In my project, layers are either text or image layer and I beileve an image layer means a comp item). Somehow the 'instanceof' method to ensure that layer should not be a comp item is not working. Please advise how to fix this error, thanks.
txt = "";
for (i = 1; i <= thisComp.numLayers; i++){
if (i == index) continue;
L = thisComp.layer(i);
if ((L.hasVideo && L.active) && !(thisComp.layer(i) instanceof CompItem)){
txt = i + " / " + thisComp.numLayers + " / " + L.text.sourceText.split(" ").length;
break;
}
}
txt
While compItem is available only in ExtendScript, you can actually check the properties available in the {my_layer}.source object.
Here's a working example (AE CC2018, CC2019 & CC2020): layer_is_comp.aep
The expression would be something similar to:
function isComp (layer)
{
try
{
/*
- used for when the layer doesn't have a ['source'] key or layer.source doesn't have a ['numLayers'] key
- ['numLayers'] is an object key available only for comp objects so it's ok to check against it
- if ['numLayers'] is not found the expression will throw an error hence the try-catch
*/
if (layer.source.numLayers) return true;
else return false;
}
catch (e)
{
return false;
}
}
try
{
// prevent an error when no layer is selected
isComp(effect("Layer Control")(1)) ? 'yes' : 'no';
}
catch (e)
{
'please select a layer';
}
For your second question, you can check if a layer is a TextLayer by verifying that it has the text.sourceText property.
Example:
function isTextLayer (layer)
{
try
{
/*
- prevent an expression error if the ['text'] object property is not found
*/
var dummyVar = layer.text.sourceText;
return true;
}
catch (e)
{
return false;
}
}
You're mixing up expressions and Extendscript. The compItem class is an Extendscript class and I'm pretty sure that it isn't available for expressions.
I'd suggest reading the docs: https://helpx.adobe.com/after-effects/user-guide.html?topic=/after-effects/morehelp/automation.ug.js

Intersection of promises and dependent computed properties

I have a user model which has 2 relations (myFriends and friendsWithMe). The intersection is the Array of users which represents the real friends. I have solved this Computatation with RSVP.all :
friends: function() {
var ret = [];
Ember.RSVP.all([this.get('myFriends'), this.get('friendsWithMe')]).then(function(results) {
ret.pushObjects(_.intersection(results[0].get('content'), results[1].get('content'))) ;
});
return ret;
}.property('myFriends.#each', 'friendsWithMe.#each'),
The Problem is now I have another computed property that depends on this one:
/**
* Gives the relation between two User
* 4: has requested your friendship
* 3: Yourself
* 2: Friends
* 1: FriendShip Request
*/
myFriendshipStatus: function() {
if(this.get('friends').contains(this.container.lookup('user:current'))){
return 2;
} else if(this.get('friendsWithMe').contains(this.container.lookup('user:current'))){
return 4;
} else if(this.get('myFriends').contains(this.container.lookup('user:current'))){
return 1;
} else if (this.get('id') === this.container.lookup('user:current').get('id')){
return 3;
} else {
return 0;
}
}.property('friends.#each')
When I now debug myFriendShipStatus the promises are not resolved and the "friends" array has no entries yet.
I have also tried to change my friends function to the ember.computed.intersect, which would then look like this:
friends: function() {
return Ember.computed.intersect('myFriends', 'friendsWithMe')
}.property('myFriends.#each', 'friendsWithMe.#each'),
But then I get an exception from this line:
if(this.get('friends').contains(this.container.lookup('user:current'))){
Because the ArrayComputedProperty has no function contains.
How can get my friends function together with myFriendShipStatus working? I would prefer to use Ember.computed.intersect, but I don't know how I check then for it's values.
The reason it returns an empty array in the first example is as follows. Immediately after the Ember.RSVP.all() call, the return statement will be executed, returning an empty ret array. At some point in the future the RSVP promise will fulfill, but since the friends function has already returned the empty array, this will have no effect.
Here is what you could do:
// See http://emberjs.com/api/#method_A
friends: Ember.A,
recalculateFriends: function() {
Ember.RSVP.all([this.get('myFriends'), this.get('friendsWithMe')]).then(function(results) {
var myFriends = results[0], friendsWithMe = results[1];
this.set('friends', _.intersection(myFriends.get('content'), friendsWithMe.get('content')));
});
}.property('myFriends', 'friendsWithMe'), // #each is redundant here
myFriendshipStatus: function() {
// Will be recalculated when the friends array changes (which will in turn recalculate when myFriends or friendsWithMe changes
}.property('friends'),
And... I'm just now noticing you're using Ember.computed.intersect wrong :P It shouldn't be wrapped inside a function:
friends: Ember.computed.intersect('myFriends', 'friendsWithMe')
(See example: http://emberjs.com/api/#method_computed_intersect),

Flex: Spark List's Indeces in View change on Orientation Change

I have a spark list with a variable row_height (2 custom itemRenderer: Header 30 px, Contact 60 px) that on the only first orientation change after a scroll, change the indexes in view.
I tried to set Header to be 60 px height, and i had no problems with the orientation change.
I'm not setting the verticalScrollPosition anywhere. Adding an event listener on the viewport's list and watching the verticalScrollPosition, it doesn't change on orientation change.
I really don't know how can i fix that.
EDIT:
This is the code relative to the list:
<fx:Script>
protected function creationCompleteHandler(event:FlexEvent):void
{
addressBookViewModel = ViewModelFactory.getInstance().getAddressBookViewModel();
addressBookViewModel.getUserContacts(onDataReceived);
}
protected function pagedContactsList_initializeHandler(event:FlexEvent):void
{
asyncListView.list = pagedContactsList;
}
private function onDataReceived():void
{
pagedContactsList.length = (BusinessContext.getInstance().getTotalContacts() + BusinessContext.getInstance().getTotalLastNames());
loadPagedData();
}
private function createPendingItemFunctionHandler(index:int, ipe:ItemPendingError):Object
{
if(!addressBookViewModel.pageUp)
{
addressBookViewModel.pageUp = true;
addressBookViewModel.currentPage++;
addressBookViewModel.getMoreUserContacts(onMoreDataRecieved, onMoreDataMissing);
}
return loadingDataHeader;
}
private function onMoreDataRecieved():void
{
loadPagedData();
}
private function loadPagedData():void
{
for(var i:int = 0; i < addressBookViewModel.contacts.length; i++)
{
pagedContactsList.setItemAt(addressBookViewModel.contacts.getItemAt(i), pagedContactsList.lastItemInsertedIndex);
pagedContactsList.lastItemInsertedIndex++;
}
addressBookViewModel.pageUp = false;
}
internal var headerItemRender:ClassFactory = new ClassFactory(HeaderItemRenderer);
internal var contactItemRenderer:ClassFactory = new ClassFactory(ContactItemRenderer);
private function rendererFunction(item:Object):ClassFactory
{
return item.hasOwnProperty("isHeader") ? headerItemRender : contactItemRenderer;
}
</fx:Script>
<fx:Declarations>
<custom:PagedArrayList id="pagedContactsList" initialize="pagedContactsList_initializeHandler(event)"/>
</fx:Declarations>
<s:List id="list" width="100%"
height="100%" itemRendererFunction="rendererFunction" change="list1_changeHandler(event)">
<s:AsyncListView id="asyncListView" createPendingItemFunction="createPendingItemFunctionHandler" />
</s:List>
The curious thing is that before and after the orientation change the list.scroller.viewport.verticalScrollPosition has the same value even if the list has scrolled ~ 40 rows. (40 is the page size).
I have many lists in my app, and every list that has const row_height has no issue, but the 2 with a variable row_height have this problem. Maybe it's caused by the AsyncListView.
EDIT 2:
I removed the AsyncListView, binding directly addressBookViewModel.contacts to the list.dataProvider, removing the pagination and the issue is still there.
EDIT 3:
I think that the only thing to do is to put breakpoints everywhere in the Scroller's class.
EDIT 4:
This issue happens only when scrolling to the bottom of the list.
EDIT 5:
Find the issue!
VerticalLayout.as, in updateDisplayListVirtual(row 1797) there's a call to a method (updateLLV) that set up a LinearLayoutVector using a typicalLayoutElement. This is lazily init with the first itemRenderer added to the dataGroup of the list. In my case it's the HeaderItemRenderer (30px).
After the updateLLV, the startIndex (index of the first visible item) is setted by calling the indexOf on the LinearLayoutVector and passing the verticalScrollPosition. (briefly: verticalScrollPosition / typicalLayoutElement.height)
The problem is that nowhere is taken into consideration the variableRowHeight!
Workaround found! Not so elegant, but it works.
stage.eventListener(StageOrientationEvent.ORIENTATION_CHANGING, yourReorientHandler, false, 1)
Setting the priority is really important, otherwise the updateDisplayListVirtual will be called before your handler.
private function reorientHandler(event:StageOrientationEvent):void
{
var IndecesInView:Vector.<int> = list.dataGroup.getItemIndicesInView();
var firstInView:int = IndecesInView[0];
callLater(
function():void
{
if(!list.layout.getScrollPositionDeltaToElement(firstInView+1)) return;
list.scroller.viewport.verticalScrollPosition += list.layout.getScrollPositionDeltaToElement(firstInView+1).y;
});
}

How *not* to destroy View when exiting a route in Ember.js

Regarding the new Ember.js routing system (described here), if I understand correctly, views are destroyed when you exit a route.
Is there any way to bypass destruction of views upon exiting a route, so that the state of the view is preserved when the user re-enters the route?
Update: Looks like, views are not destroyed unless the outlet view is being replaced in the new route. For e.g., if you are in stateA with ViewA in some {{outlet master}} and you go to stateB with ViewB in {{outlet master}}, then ViewB will replace ViewA. A way around this is to define multiple outlets when you need to preserve views, e.g., {{outlet master1}}, {{outlet master2}}, ...
A nice feature would be the ability to pass an array of views to the outlet. And also be able to choose whether views will be destroyed or just become hidden, upon exiting a route.
I have since figure out how to modify the routing system, so that views inserted into outlets are not destroyed. First I override the Handlebars outlet helper, so that it loads an Ember.OutletView into {{outlet}}:
Ember.Handlebars.registerHelper('outlet', function(property, options) {
if (property && property.data && property.data.isRenderData) {
options = property;
property = 'view';
}
options.hash.currentViewBinding = "controller." + property;
return Ember.Handlebars.helpers.view.call(this, Ember.OutletView, options);
});
Where Ember.OutletView extends Ember.ContainerView as follows:
Ember.OutletView = Ember.ContainerView.extend({
childViews: [],
_currentViewWillChange: Ember.beforeObserver( function() {
var childViews = this.get('childViews');
// Instead of removing currentView, just hide all childViews
childViews.setEach('isVisible', false);
}, 'currentView'),
_currentViewDidChange: Ember.observer( function() {
var childViews = this.get('childViews'),
currentView = this.get('currentView');
if (currentView) {
// Check if currentView is already within childViews array
// TODO: test
var alreadyPresent = childViews.find( function(child) {
if (Ember.View.isEqual(currentView, child, [])) {
return true;
}
});
if (!!alreadyPresent) {
alreadyPresent.set('isVisible', true);
} else {
childViews.pushObject(currentView);
}
}
}, 'currentView')
});
Basically we override _currentViewWillChange() and just hide all childViews instead of removing the currentView. Then in _currentViewDidChange() we check if the currentView is already inside childViews and act accordingly. The Ember.View.isEqual is a modified version of Underscore isEqual:
Ember.View.reopenClass({
isEqual: function(a, b, stack) {
// Identical objects are equal. `0 === -0`, but they aren't identical.
// See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
if (a === b) return a !== 0 || 1 / a == 1 / b;
// A strict comparison is necessary because `null == undefined`.
if (a == null || b == null) return a === b;
// Unwrap any wrapped objects.
if (a._chain) a = a._wrapped;
if (b._chain) b = b._wrapped;
// Compare `[[Class]]` names.
var className = toString.call(a);
if (className != toString.call(b)) return false;
if (typeof a != 'object' || typeof b != 'object') return false;
// Assume equality for cyclic structures. The algorithm for detecting cyclic
// structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
var length = stack.length;
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (stack[length] == a) return true;
}
// Add the first object to the stack of traversed objects.
stack.push(a);
var size = 0, result = true;
// Recursively compare objects and arrays.
if (className == '[object Array]') {
// Compare array lengths to determine if a deep comparison is necessary.
size = a.length;
result = size == b.length;
if (result) {
// Deep compare the contents, ignoring non-numeric properties.
while (size--) {
// Ensure commutative equality for sparse arrays.
if (!(result = size in a == size in b && this.isEqual(a[size], b[size], stack))) break;
}
}
} else {
// Objects with different constructors are not equivalent.
if (a.get('constructor').toString() != b.get('constructor').toString()) {
return false;
}
// Deep compare objects.
for (var key in a) {
if (a.hasOwnProperty(key)) {
// Count the expected number of properties.
size++;
// Deep compare each member.
if ( !(result = b.hasOwnProperty(key) )) break;
}
}
}
// Remove the first object from the stack of traversed objects.
stack.pop();
return result;
}
});
So that the state of the view is preserved when the user re-enters the
route.
I would, instead, store that information in the controller (or the state manager) so that when the route is re-entered, the new view is initialized with the old state. Does that make sense? So, for example, if it's a list of posts, and one is selected, you would store the data about which post was selected in the controller (or the state manager). After visiting a specific post and then coming back to the list, that same post would be selected.
I can imagine a use case where this wouldn't be very useful (e.g. scrolling to a specific position in a long list) so maybe that doesn't answer your question.