Add an HTML class to a DOM element controlled by two.js - javascript

I'm trying to add a class and ID to specific Two.js objects in this project: http://itpblog.evejweinberg.com/Homework/Open/ (click a few times to play)
If I console.log the word 'background' I see that these are two.js objects but I can't seem to use css or jquery to add a class/ID to them.
Any help is appreciated!
I even tried adding it to the whole project but that did not work:
$(document.body).addClass("dropshadow");

two.js entities are not DOM elements themselves, but each Scene, Group, or Polygon contains at least one reference to the DOM element that gets drawn when the entity is changed. To reference various DOM elements use the following syntaxes:
// Initialize two.js and attach to a dom element referenced by `canvas`
var two = new Two(params).appendTo(canvas);
// Two.Scene
var my_scene = two.renderer.domElement;
// Two.Group
var my_group = document.getElementById(two.scene.id);
// Two.Polygon — requires knowing the ID by means of your custom app logic.
var my_poly = document.getElementById(my_poly_html_id);
my_poly.classList.add('my-class');
Here's a screenshot showing all three commands in an actual app along with the outcome of each, with one additional command add a class to the shape that was targeted. The syntax of the last command differs but I omitted the var statements so that the console would display the result instead of outputting undefined.
If you'd like to create custom HTML IDs for individual shapes, use the .id setter before the initial render of your shape. Since most of this code is just setup, I offer a practical example on one of my own projects. In that snippet, a shape variable holds a new instance of Two.Polygon so calling shape.id = 'something-unique' before calling two.update() to draw the shape for the first time results in a DOM element with a custom HTML ID. Here is an incomplete block of setup code showing how to set the ID:
// Create new shape
var shape = two.makeRectangle(START_X, START_Y, START_WIDTH, START_HEIGHT);
// Set custom ID
shape.id = 'shape-' + Math.random(10000000);
// Draw shape for first time.
two.update();

Related

Issue with an event from a javascript widget (Tradingview) where only first added event is triggered when created on a loop

I have the following issue with a javascript chart widget Im using. I think my issue is more to do with my logic than with a problem with the chart library itself. I have already asked this on their GitHub repo, but again I believe this is just me not doing this properly.
This javascript widget provides events that I can act upon. This is a javascript library from TradingView (chart library), it has a function to create a line on the chart. This function is called .createOrderLine(). When you create an orderLine, it returns an object that you can manipulate (set price, events, etc)
This object has an event called onMove(), with a callback function that I can write code to. So what I am doing is, looping through an array of orders and creating a line on the chart for each order that exists. So every time I move a line on the chart, this callback is called.
When the chart is loaded initially, I add each line object to a Map by setting its key to the orderID and the value to the object itself. If I can’t find the orderID on the map, I will set it to the map.
The issue Im having that I can not figure out is, every time I move ANY of the lines created, only the code from the first order added is triggered, ie: the console.log(order.OrderID) always returns the id of the first line created, no matter which line I move. So in essence, it seems the onMove() from the first order is the only one that runs.
Here is some simplified version of my logic / code:
var objectMapOrders = new Map();
for(var order of currentSelectedMarketOrderIds){
var apiOrderObject = objectMapOrders.get(parseInt(order.OrderID))
if(!apiOrderObject){
var apiOrderObject = widget.activeChart()
.createOrderLine()
.setPrice(order.EntryPrice)
objectMapOrders.set(parseInt(order.OrderID), apiOrderObject);
}else{
apiOrderObject
.setPrice(order.EntryPrice)
.onMove(async function() {
//Call function that updates the order price
console.log(order.OrderID)
updateOrder(order.OrderID,this.price())
})
}
}
Not sure if Im using the Map correctly or if there’s an alternative way that I can make this work?
I have tried all sorts of changes around (setting the onMove on inside each if block) to no avail

How to get all possible valid attributes on a DOM element [duplicate]

This question already has answers here:
How to list all element attributes in JS?
(3 answers)
Closed 5 years ago.
Please note that .attributes only gets the current attributes, which is not what this question is about.
I want a way to get all the attributes of a DOM element. Not just the ones that are on it now, but the ones that are possible in the future too.
The specific use case is to find the potential attributes in an SVGElement that aren't in an HTMLElement - there's a list on MDN (SVG Attribute reference), but, for obvious reasons, hardcoding is not a good idea.
My initial thought was to iterate through the prototype chain of an instance of each and compare the two lists (with basic filtering for event handlers), but this doesn't actually give the potential svg attributes.
EDIT
IMPORTANT NOTE - pasting your answer code into the console on this page and using document.body as a target should show a list of over 50 attributes, including things like contentEditable, contextMenu, dir, style, etc.
This also needs to work cross-browser.
Could something like this be what you're looking for?
It looks like a DOM element object stores empty keys for all possible attributes. Could you loop over these keys and store them in an array, then from there use something similar to filter out inherited attributes?
HTML
<svg id="blah"></svg>
Javascript
const blah = document.getElementById('blah')
let possibleKeys = []
for (let key in blah) {
possibleKeys.push(key)
}
Here's a JSBin example ... it looks like it produces a list of all possible attributes but it would need some filtering.
See also this thread.
How to list all element attributes in JS?
Any one of these should work because they return a live HTMLCollection.
var svgElement = window.document.getElementsByClassName("someSvgClass")[0];
//assume someSvgClass is on svg element.
//var svgElement = window.document.getElementsByTagName("svg")[0];
//var svgElement = window.document.getElementsByName("mySvg")[0];
//assume svg has this name.
var svgAttributes = svgElement.attributes;
for(let i=0; i<svgAttributes.length; i++) {
console.log(svgAttributes[i]);
}
See the below documentation from MDN on getElementsByTagName()
The Element.getElementsByTagName() method returns a live
HTMLCollection of elements with the given tag name. The subtree
underneath the specified element is searched, excluding the element
itself. The returned list is live, meaning that it updates itself with
the DOM tree automatically. Consequently, there is no need to call
several times Element.getElementsByTagName() with the same element and
arguments.
The documentation for getElementsByName , and getElementsByClassName say the same thing; a live node list is returned. If you'd like to try it, I created a fiddle here.
You'll see that svgAttributes list is automatically updated upon clicking "Add Attribute" without re-executing any of those functions.
There is no API for that and I don't think a workaround is possible because when you change an attribute on a current DOM node, the browser is responsible for re-rendering and updating the webpage in a low-level way that is not exposed to the JavaScript context.
Also, keep in mind that any correctly formatted attribute is actually valid in the context of a DOM tree, even though it might not trigger any change at the rendering level or in the way the browser renders the page. Especially the data-* attributes.
There might be some vendor-specific API but that wouldn't be useful if you want cross-browser compatibility.
You need to hardcode it, sadly. Given that you specifically want the SVGElement attributes, maybe you can scrape the W3's SVG standard document to automatically create the list?
Edit: I made a snippet to easily scrape the values from the standard:
const uniq = arr => Array.from(new Set(arr))
const nameElements = document.querySelectorAll('table[summary="Alphabetic list of attributes"] .attr-name')
const arrNameElements = Array.prototype.slice.call(nameElements)
const svgAttributes = uniq(arrNameElements.map(el => el.innerText.replace(/\‘|\’/g, '')))
Just execute it on the svg attributes page, by opening the dev console on the page and pasting in this code :)
Edit 2: I forgot the presentation attributes. I'll let you figure that one out ;)

Programmatically add/delete polymer element

Does the remove child method provided by polymer takes care of cleaning all the dependencies such as event listeners, binded vars, etc. ?
Polymer.dom(parent).removeChild(node)
I want to add/remove many elements programmatically and want to make sure nothing is leaking or nothing is still watching for objects that do not exist anymore.
To add:
// Create the element
var paperListbox = document.createElement('paper-listbox');
paperListbox.setAttribute('depth', depth);
this.listen(paperListbox, 'iron-select', 'selectionChanged');
// add it
Polymer.dom(this.$.container).appendChild(paperListbox);
To remove:
// get node of interest
var node0 = Polymer.dom(this.$container).childNodes[0];
Polymer.dom(this.$.container).removeChild(node0)
Does such a pattern would allow me to add/remove lot of elements properly?

DocumentApp Script - Merge cell not working

cell.appendTable([["Hello"],["Hello","I","J"]])
Outputs to:
|Hello|
|Hello|I |J |
I want to merge the first row.
Developed in scripts.google.com DocumentApp. - With Table And Cell Element
If you were expecting to have a merged cell that, like what you can do in a spreadsheet, that is not possible. Simply because that's not possible in Google Documents (at least not yet). Therefore the API cannot do this (it can only do things that are also possible manually).
Try merge() function : Merges the element with the preceding sibling of the same type.
Only elements of the same ElementType may be merged. Any child
elements contained in the current element are moved to the preceding
sibling element.
The current element is removed from the document.
var body = DocumentApp.getActiveDocument().getBody();
// Append two paragraphs to the document.
var par1 = body.appendParagraph('Paragraph 1.');
var par2 = body.appendParagraph('Paragraph 2.');
// Merge the newly added paragraphs into a single paragraph.
par2.merge();
Reference
Found Answer.
Merge Cell Functionality didn't supported by Google App Script yet.

d3 create object without appending

I'm using d3 for graphing, and I'm trying to create an svg object, to add to the DOM later.
I used to have
var svg = d3.select(el).append("svg");
var graph = svg.append("g")
...etc...
and for reasons I won't go into, I wanted to create the svg element before appending it to the DOM.
So I did
var svg = d3.select(document.createElementNS(d3.ns.prefix.svg, 'svg'))
var graph = svg.append("g")
...etc...
, which works, and while debugging, I can see that svg is a 1-element array, with the children nicely attached.
The problem comes at the append step:
d3.select(el).append(svg);
There, I get an error Error: Failed to execute 'createElementNS' on 'Document': The qualified name provided ('[object SVGSVGElement]') contains the invalid name-start character '['. I've taken a look here: How to create "svg" object without appending it? but it seems that's exactly how they suggest it.
Any idea why this is so? I've tried appending svg[0], but no luck either. It seems append() only takes strings as an argument.
edit: the d3 reference at https://github.com/mbostock/d3/wiki/Selections#append states
selection.append(name)
... ... ...
"The name may be specified either as a constant string or as a function that returns the DOM element to append."
Consequently I've tried
d3.select(el).append(function(){return svg;});
but that fails with a Error: Failed to execute 'appendChild' on 'Node': The new child element is null.
If svg is a selection, svg.node() returns the DOM element, e.g.:
d3.select(el).append(function(){return svg.node();});
(Mind you, I'm not certain that svg in your case is a true selection, but you could give it a try.)
You might be better off using the regular element.appendChild function for this.
You can get a reference to your parent element using d3.select(el).node() then, you can call .appendChild on that, passing in svg.node() as the element to append.
So, all together:
d3.select(el).node().appendChild(svg.node());

Categories

Resources