Change the cursor icon in viewer - autodesk-forge

I am looking to change the cursor in the viewer when I activate my tool in the viewer. I have tried updating the cursor CSS value for the canvas of the viewer but it seems to be overwritten to the default viewer one.

You should show what you've tried.
If you add this css:
.adsk-viewing-viewer > .canvas-wrap > canvas {
cursor: pointer !important;
}
Just replace 'cursor: pointer' with the type of cursor you'd like. Be sure to add the !important value or it won't override the default cursor.
The canvas is generated after the document is ready, so you'd need to wait for the appropriate events if you are looking to override the cursor style with JS.
Edit:
I noticed you said you were activating it from a tool, so to set the cursor like this with js:
const viewerCanvas = document.getElementsByTagName('canvas')[0] //may need to ensure [0] is the viewer canvas if multiple canvas's
viewerCanvas.setAttribute('style', 'cursor: pointer !important');
You just need to unsure that you handle both tool-activated and tool-deactivated toggle events.

Try this to set the cursor style:
viewer.canvas.style.cursor = "pointer" | "progress" ...
And beware that that'd be overwritten again when navigation tools are activated so to stick to a cursor at all times follow the other answer to override by class name in your stylesheet with the !important rule.

As I stumbled across the same problem I found the way other tools implement this behavior:
You can set the cursor by implementing the getCursor function in your tool (your tool must be active and have the highest priority). This seems to be the easiest and safest method to set the mouse cursor. Also note that an cursor image should be 32x32px for best compability according to mozilla.
Look in the OrbitDollyPanTool for an example:
this.getCursor = function ()
{
if (!_useCustomCursors)
return null;
switch (_activeMode) {
case "freeorbit":
case "orbit":
return 'url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAt1BMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8AAAAzMzP6+vri4uISEhKKioqtra2dnZ2EhIR9fX10dHRkZGQdHR3t7e3Hx8e5ubm1tbWoqKhWVlZKSko4ODgICAjv7+/o6OjMzMyxsbFOTk4pKSkXFxcEBAT29vbW1tZ6enpISEgLCwvhzeX+AAAAGXRSTlMANRO0nHRJHfnskIxQRKh89syDVwTWZjEJxPFEswAAAOFJREFUKM+1j+lygkAQhIflEAJe0Rw9u4CCeKKoSTTX+z9XoMJWWeX+ssrvZ3f19DQ5zOw/0DUMQPlmQ72bE2adBp8/Rp3CQUi3ILx+bxj4fjDs9T1Bmo6bbPPN8aDU4bjJt4nb+de789kSFyxn826jW3ICLNZZKU8nWWbrBTCRVm04U8TpjquRFf1Go0d7l8aYOrUR7FGEFr1S9LGymwthgX2gE/Kl0cHPOtF2xOWZ5QpIC93RflW4InkDoPRXesd5LJIMQPzV7tCMa7f6BvhJL79AVDmYTNQ1NhnxbI/uwB8H5Bjd4zQPBAAAAABJRU5ErkJggg==), auto';
case "dolly":
return "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAAAgVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD///8mJiYAAADNzc2/v7+fn59paWlPT08MDAwICAj6+vqpqak7Ozv29vby8vLp6em2traAgIBkZGRZWVlAQEAaGhpISEgkS7tbAAAAFHRSTlMAOvhpZD8mkQWegMy9qY1YVE01EYiqlE0AAADZSURBVCjPbY9ZloMgEAAbEbfsmRZZXbJn7n/AAX2RQVN/VD26AXLOeZLDGo6IbfI9tHq8cdxuj1HwvgCoaiHqKoRk+M3hB9jueUW8PnfsE/bJ3vms7nCkq7NoE3s99AXxoh8vFoXCpknrn5faAuJCenT0xPkYqnxQFJaU0gdZrsKm8aHZrAIffBj40mc1jsTfIJRWegq6opTMvlfqLqYg7kr1ZB7jFgeaMC59N//8O4WZ1IiPF8b5wMHcJn8zB4g4mc77zpxgAbMSUVoGK4iV0hL4wrksz+H0Bw5+E+HrniDQAAAAAElFTkSuQmCC), auto";
case "pan":
return "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAMAAADXqc3KAAABHVBMVEUAAABPTk4AAAAAAAAJCQkRERE0MzQQEBAODg4QEBB4d3dbWlo9PDw/Pj4vLy8sLCwZGBgWFhYcHBwKCgoSEhIAAAAKCgoICAgKCgoQEBAODg4EBAQICAgPDw8REREMDAx2dnY0NDQvLy9QUFAaGhomJSYjIyM7OjokJCQNDA0mJiYNDQ0AAAAUFBQJCQkQEBAEBAQNDQ0PDw8VFRX///+amJkAAAD5+fnz8/PKycn9/f339vbi4eLR0dDNzMyAgIB8e3xycHH7+/vw7+/o6OjX1ta7urq4t7iwsLCnp6eioqKbmppva21OTk74+Pjl5eXc3Nzb29vLy8vDw8PDwsKrqqqdnZ2WlpaSkpKTkZKMiouEg4NkZGRISEgxLzBpgbsEAAAANHRSTlMA+fiQXgngKSYG/vX17uvBuqackpCNg3BpUkpAPBwTDvj18+vl0s/NwrOwoZZ+TDg4NBkBGrzX8QAAAP5JREFUKM99j9Vuw0AQRdeuKZyGkyZNmbnXDLHDVGb8/8/oy7paK1bO0+oc7WiGnGiaxq+QRTQAOh8f9Jv4H/Ge8PZPrCdlvkxfYluUT2WyyCq3mZ7unwlKVLcqOzA/Mf71j0TWJ/Ym6rPeca05Ni4iIevYc7yoUD2zQFhq71BdI9nvBeBabFDSPe8DswlUc1Riw3VxbH0NHBUPQ0jrbDnPYDjALQBMq9E7nkC5y7VDKTZlUg8Q0lmjvl74zlYErgvKa42GPKf3/a0kQmYCDY1SYMDosqMoiWrGwz/uAbNvc/fNon4kXRKGq+PUo2Mb96afV0iUxqGU2s4VBbKUP65NL/LKF+7ZAAAAAElFTkSuQmCC), auto";}
return null;
};

Related

Is there a way to show markup in the viewer outside of editMode?

I'm looking for a way to show markups when not in editMode. I want to be able to draw markups in the viewer while at the same time being able to use edit2D. Everytime I call leaveEditMode() on the markups extension, the markups disappear. If there was just a way to have them always showing even when not in edit mode, that would do the trick. I have seen stuff about a view mode but the enterViewMode() must be outdated as I cannot find it.
Another option would be to leave edit mode on in the markups extension and also use the edit2D tools simultaneously by changing which drawing layer/canvas is on top? I have no idea if that's possible or how to go about it though.
Any ideas would be helpful!
Okay so I figured out a way, I'm not sure what the repurcussions would be, but it seems to work.
Here's an edited code snippet I threw together quick to test and it seems to work. Basically I do the opposite of what enterEditMode() and leaveEditMode() already do. Basically markupsExtension.editModeSvgLayerNode holds the svg data for all the markups. When leaveEditMode() is called, it clears out markupsExtension.svg. So I just add it back after it's called manually. I also clear it out before re-entering because it does it on it's own and it might interfere.
if (buttonName === 'markup') {
let markupsExtension = this.viewer.getExtension('Autodesk.Viewing.MarkupsCore');
if (this.selectedButton === buttonName) {
// Exit markups
markupsExtension.leaveEditMode();
// Shows the markup after leaving
if (markupsExtension.editModeSvgLayerNode.svg) {
markupsExtension.svg.appendChild(markupsExtension.editModeSvgLayerNode.svg);
}
}
else {
this.selectedButton = buttonName;
// Remove the svg set we added so it can redraw it in "enterEditMode()"
if (markupsExtension.editModeSvgLayerNode && markupsExtension.editModeSvgLayerNode.svg.parentNode) {
markupsExtension.svg.removeChild(markupsExtension.editModeSvgLayerNode.svg);
}
markupsExtension.enterEditMode();
}
}

Add custom cursor to CSS stylesheet via JS prompt

I'm trying to make a custom cursor setter. You can customize cursors in CSS, so I went there first.
html {
cursor: url(MY URL GOES HERE), auto !important;
}
It works at this point. However, I want the average user to be able to enter an image URL and see the cursor change to that. I decided to use JavaScript to do that.
function customCursor() {
var v1 = prompt("Enter the image URL you want to be your mouse cursor.");
var style = document.createElement('style');
style.innerHTML = `html {cursor:url(` + v1 + `); } `;
document.head.appendChild(style);
}
However, it doesn't work. I checked the current page HTML with Firebug, and the tag is added. And when I use JavaScript to add it manually, it works. So why would it not work?
I also made sure to keep the images I chose below 128x128.
After massive changes to the code, it still is not working. However, I now understand a reason why (by using devtools to read what was actually being added):
Instead of dynamically using my variable, it was treating the variable name as the URL itself. This makes this question mostly irrelevant.

Polymer - cloneNode including __data

I am using the library dragula for doing some drag & drop stuff.
Dragula internally uses cloneNode(true) to create a copy of the dragged element that will be appended to the body to show the preview image while dragging.
Unfortunately, if dragging a polymer element, the bound data get's not cloned. By consequence the contents of the dragged element (e.g. <div>[[someString]]</div>) are empty.
Is there a solution for this?
I actually do not need the data to be bound for my element, it is just a "read-only" element that displays some data that does not change after being initialized. Is there maybe a way to somehow "resolve" the strings to the html without being bound anymore?
Thank you already!
Found a solution myself. You have to override the cloneNode method inside the polymer class:
cloneNode(deep) {
let cloned = super.cloneNode(deep);
for (let prop in MyClass.properties) {
cloned[prop] = this[prop];
}
return cloned;
}

DropEffect semantic for HTML5 drag and drop

According to the HTML5 specs the dropEffect property on a drop target allows the drop target to select the desired drop effect. The drag and drop framework should combine this with the effectAllowed property set by the drag source to display the matching visual feedback (typically a specific cursor depending on the operation).
I was however not able to use this feature consistently across browsers. It seems to work for Chrome and Opera as expected but doe not for IE and FF (although the developer documentation for each browsers explicitly documents it).
I have put together a sample on JSFiddle: http://jsfiddle.net/cleue/zT87T/
function onDragStart(element, event) {
var dataTransfer = event.dataTransfer,
effect = element.innerText || element.textContent;
dataTransfer.effectAllowed = effect;
dataTransfer.setData("Text", effect);
dataTransfer.setDragImage(element, 0, 0);
}
function onDragEnter(element, event) {
var dataTransfer = event.dataTransfer,
effect = element.innerText || element.textContent;
dataTransfer.dropEffect = effect;
event.preventDefault();
}
function onDragOver(element, event) {
var dataTransfer = event.dataTransfer,
effect = element.innerText || element.textContent;
dataTransfer.dropEffect = effect;
event.preventDefault();
}
Is this sample incorrect or my understanding of the purpose of this feature or are these browser bugs?
i had exactly the same problem and came to the same conclusion as yourself, it just doesn't work. In addition to changing the mouse cursor there is the job of working out at the source element what took place - from the spec you can listen to dragend and e.g. remove the element if the drop effect was move and leave it if it were copy. That doesn't work consistently either. I asked the question here, i put a longish explanation with all my findings.
btw - i see it says that drag and drop is at risk from being removed due to a lack of implementation which is a pity.

mootools - using addEvent to element not working properly?

bangin' my head against this and it's starting to hurt.
I'm having trouble with adding an event to an element.
I'm able to add the event, and then call it immediately with element.fireEvent('click'), but once the element is attached to the DOM, it does not react to the click.
example code:
var el = new Element('strong').setStyle('cursor','pointer');
el.addEvent('click',function () { alert('hi!'); });
el.replaces(old_element); // you can assume old_element exists
el.fireEvent('click'); // alert fires
however, once I attach this to the DOM, the element is not reactive to the click. styles stick (cursor is pointer when I mouseover), but no event fires. tried mouseover as well, to no avail.
any clues here? am I missing something basic? I am doing this all over the place, but in this one instance it doesn't work.
EDIT----------------
ok here's some more code. unfortunately I can't expose the real code, as it's for a project that is still under tight wraps.
basically, the nodes all get picked up as "replaceable", then the json found in the rel="" attribute sets the stage for what it should be replaced by. In this particular instance, the replaced element is a user name that should pop up some info when clicked.
again, if I fire the event directly after attaching it, all is good, but the element does not react to the click once it's attached.
HTML-----------
<p>Example: <span class='_mootpl_' rel="{'text':'foo','tag':'strong','event':'click','action':'MyAction','params':{'var1': 'val1','var2': 'val2'}}"></span></p>
JAVASCRIPT-----
assumptions:
1. below two functions are part of a larger class
2. ROOTELEMENT is set at initialize()
3. MyAction is defined before any parsing takes place (and is properly handled on the .fireEvent() test)
parseTemplate: function() {
this.ROOTELEMENT.getElements('span._mootpl_').each(function(el) {
var _c = JSON.decode(el.get('rel'));
var new_el = this.get_replace_element(_c); // sets up the base element
if (_c.hasOwnProperty('event')) {
new_el = this.attach_event(new_el, _c);
}
});
},
attach_event: function(el, _c) {
el.store(_c.event+'-action',_c.action);
el.store('params',_c.params);
el.addEvent(_c.event, function() {
eval(this.retrieve('click-action') + '(this);');
}).setStyle('cursor','pointer');
return el;
},
Works just fine. Test case: http://jsfiddle.net/2GX66/
debugging this is not easy when you lack content / DOM.
first - do you use event delegation or have event handlers on a parent / the parent element that do event.stop()?
if so, replace with event.preventDefault()
second thing to do. do not replace an element but put it somewhere else in the DOM - like document.body's first node and see if it works there.
if it does work elsewhere, see #1
though I realsie you said 'example code', you should write this as:
new Element('strong', {
styles: {
cursor: "pointer"
},
events: {
click: function(event) {
console.log("hi");
}
}
}).replaces(old_element);
no point in doing 3 separate statements and saving a reference if you are not going to reuse it. you really ought to show the ACTUAL code if you need advice, though. in this snippet you don't even set content text so the element won't show if it's inline. could it be a styling issue, what is the display on the element, inline? inline-block?
can you assign it a class that changes it on a :hover pseudo and see it do it? mind you, you say the cursor sticks which means you can mouseover it - hence css works. this also eliminates the possibility of having any element shims above it / transparent els that can prevent the event from bubbling.
finally. assign it an id in the making. assign the event to a parent element via:
parentEl.addEvent("click:relay(strong#idhere)", fn);
and see if it works that way (you need Element.delegate from mootools-more)
good luck, gotta love the weird problems - makes our job worth doing. it wouldn't be the worst thing to post a url or JSFIDDLE too...