How to create two level context menu in autodesk forge - autodesk-forge

I want to creat two level context menu but there is no api for this.Just look like this
level context menu image
what I can do?

It is rather straighforward to acheive a multi level context menu by deriving from Autodesk.Viewing.UI.ObjectContextMenu. Simply provide an array in the target field:
buildMenu (event, node) {
var menu = []
switch (node.type) {
case 'hubs':
menu.push({
title: 'Show details',
className: 'fa fa-share',
target: [{
title: 'Hub details',
className: 'fa fa-cloud',
target: () => {
this.emit('context.details', {
event, node, type: 'hubs'
})
}
}, {
title: 'Projects details',
className: 'fa fa-folder',
target: () => {
this.emit('context.details', {
event, node, type: 'hubs.projects'
})
}
}]
})
break
A complete example of this can be found here: DataContextMenu.js

Unfortunately, it's not available on current viewer version. You might have to write your own context menu in deep. But there is a workaround that you can follow:
Override functions of Autodesk.Viewing.Private.ContextMenu to provide multiple level menus.
Refer codes from Autodesk.Viewing.UI.ObjectContextMenu, then create your owned ObjectContextMenu and replace contextMenu property with the your owned multiple levels ContextMenu from the step 1.
Refer codes from Autodesk.Viewing.Extensions.ViewerObjectContextMenu, then write your owned ViewerObjectContextMenu that inherits the custom ObjectContextMenu from the step 2.
P.S. This is just a workaround, it's not the formal solution, you might have to use it at your own risk.

Related

Is there a way to create hyperlink within Vue argument

I have a function that creates a text box that alters within each name. The thing is, I want one of these description arguments to allow a hyperlink within the text.
example:
var maps = new Vue({
el: "#maps",
data: {
selected: 'US County'
maps = [
{
name: 'US County'
description: "This is where I want my **hyperlink** to go"
}
]
}
})
I want the hyperlink to be within this description argument among separate text..I tried using <a href... but it wasn't working.
I am relatively new to HTML and Vue JS so I apologize if this question does not entirely make sense.
If using Vue 2, check out this page, which shows how to bind a variable and display it as HTML. You will also want to be sure to store your description + HTML as a template literal
Template should be something similar to:
<template>
<div v-html="maps[0].description"></div>
</template>
Notice the backticks in the description. This is called a template literal. Your script should be similar to the following:
var maps = new Vue({
el: "#maps",
data: {
selected: 'US County'
maps = [
{
name: 'US County'
description: `This is where I want my link to go`
}
]
}
})

Vega-Lite: "1 in X" custom legend labels

I'm working on a choropleth map that shows the share of the population that has confirmed positive case of Covid-19 in each political jurisdiction. Similar to this example in the per capita Mapbox graphic on this page of the The New York Times.
I figured out just about every detail expect how to customize the legend. Currently, the labels display the shareOfPop as a number. Though, I want to prefix each label with "1 in ${shareOfPop}", and to add a suffix to the final label "1 in ${shareOfPop} or more".
enter image description here.
I've created this map in an Observable Notebook.
Things I've tried so far...
Making us of the custom legend encodings
To specify label text:
vl.color()
.fieldQ('shareOfPop')
.scale(
{
scheme: "yelloworangered",
domain: [250, 10],
clamp: true,
}
)
.legend({
title: "Share of Pop.",
encode: {
labels: {text: "1 in ${datum.value}"}
}
})
Register a custom formatter
Which I doubt I've accomplished correctly.
Here's what my configuration looks like (which is based on the config in the Introduction to Vega-Lite notebook).
vl = {
const [vega, vegalite, api, tooltip] = await Promise.all([
'vega#5.13.0',
'vega-lite#4.14.1',
'vega-lite-api#0.11.0',
'vega-tooltip#0.22.1'
].map(module => require(module)));
const options = {
config: {
// allow custom format types
customFormatTypes: true,
config: {
view: {continuousWidth: 400, continuousHeight: 300},
mark: {tooltip: null}
}
},
init: view => {
// initialize tooltip handler
view.tooltip(new tooltip.Handler().call);
// enable horizontal scrolling for large plots
if (view.container()) view.container().style['overflow-x'] = 'auto';
// register a custom expression function...am I doing this right???
vega.expressionFunction('1inX', function(datum) {
return `1 in ${datum}`
})
},
view: {
// view constructor options
loader: vega.loader({baseURL: 'https://cdn.jsdelivr.net/npm/vega-datasets#1/'}),
renderer: 'canvas'
}
};
return api.register(vega, vegalite, options);
}
Then I specify this custom formatType when defining the mark:
vl.color()
.fieldQ('shareOfPop')
.scale(
{
scheme: "yelloworangered",
domain: [250, 10],
clamp: true,
}
)
.legend({
title: "Share of Pop.",
formatType: "1inX",
})
)
Neither of these approaches produced any noticeable change.
Gonna answer my own question here.
Turns out Legend has a general labelExpr property that allows you to specify a Vega expression for customizing the label.
In my case, I wanted to always prepend the string "1 in ", and also append "+" when over may domain limit. Here's how I did it using the join() and if() functions.
...
vl.color()
.legend(
{
labelExpr: "join(['1 in ', datum.value, if(datum.value >= 250, '+', '')], '')"
}
)
This property isn't documented for Legend, though it is for for Axis).

is there a way to tell which markers are being clustered using vue2-google-maps and marker-clusterer-plus

Hello Everyone I would like to find out if there is a way to tell what custom markers are being clustered and also if there is a way to listen to the change of the markers being declustered on zoom in?
<template>
<gmap-map
ref="gmap"
:options="{
disableDefaultUi: true,
scaleControl: false,
streetViewControl: false,
rotateControl: false,
fullscreenControl: false,
scrollwheel: false,
clickableIcons: false
}"
:center="center.hasOwnProperty('lat') ? center : markers[0].position"
:zoom="10"
:style="{ width: width, height: height }"
>
<gmap-cluster
:gridSize="30"
:zoomOnClick="true"
:enableRetinaIcons="true"
:minimumClusterSize="3"
ref="cluster"
#click="clusteredMarkers($event)"
>
<gmap-custom-marker
v-for="(m, index) in markers"
:key="index"
:id="index"
:marker="m.position"
ref="marker"
>
<v-avatar color="primary" size="25">
<span
#click="center = m.position"
#mouseover="$emit('changeEl', index + 1)"
#mouseleave="$emit('changeEl', '')"
size="15"
:class="
hoveringEl - 1 === index ? 'white--text' : 'white--text'
"
>{{ index + 1 }}</span
>
</v-avatar>
</gmap-custom-marker>
</gmap-cluster>
</gmap-map>
</template>
My Script looks like this:
<script>
import GmapCustomMarker from 'vue2-gmap-custom-marker';
import GmapCluster from 'vue2-google-maps/dist/components/cluster';
export default {
name: 'GoogleMap',
components: {
GmapCustomMarker,
GmapCluster
},
props: {
markers: {
type: [Object, Array],
required: false
},
},
data() {
return {
center: {},
places: [],
currentPlace: null
};
},
methods: {
clusteredMarkers(event) {
console.log(event.getMarkers());
}
}
};
</script>
I had to remove sensitive information and left what I think is required to see the full scope of the issue. Please let me know if you need additional information.
On my console I get the right amount of markers when I click on the cluster but not sure how to identify them within my markers. Also I added an Id to the gmap-custom-marker and when I console.log(this.$refs.marker) I get access to that Id but not sure how to identify if is on the cluster or not. Any ideas on how to proceed?
I solved the problem for gmap-marker - this is what worked for me, might be relevant to custom marker component too.
In method at #click event of cluster object - the handler method receives Cluster object, which contains function getMarkers that returns list of markers in some obscure format, rather than actual list of markers. But those markers have getTitle method, which pulls info that was set as title prop of gmap-marker component in the template. So, by setting some sort of id at that prop plus for each marker, it's possible to map cluster's "markers" to your markers.
Script example:
toggleClusterInfo(cluster: Cluster) {
//* Extract markers id list from cluster
const markersIdList: string[] = []
const gmapMarkers: { getTitle: () => string }[] = cluster.getMarkers()
gmapMarkers.forEach((m) => markersIdList.push(m.getTitle()))
// TODO: markersIdList contains list of values at `title` prop for each marker
// use it to map to objects itself.
}
And template example (important to set title prop to marker):
<GmapCluster #click="toggleClusterInfo">
<GmapMarker
v-for="m in markers"
:key="m.id"
:title="m.id"
:position="m.position"
:clickable="true"
></GmapMarker>
</GmapCluster>
Relevant info at this SO question:
how to find the markers in the individual clusters in a marker cluster object in google maps api v3?

Adding a button to Navigator to exercise a choice

Navigator contains a feature where users can define their own table views, see DAML docs for Navigator.
Is it possible to create a view where one column renders a button that, when clicked, immediately exercises a choice?
Yes, this is possible. The customized views allow you to render arbitrary React components, so let's create one to exercise a choice.
First, start with a working frontend-config.js file. The DAML quickstart project contains one.
Then, make sure you import at least the following symbols at the top of the file:
import React from 'react';
import { Button, DamlLfValue, withExercise } from '#da/ui-core';
Then, define the following top level values (for example, just below export const version={...}):
// Create a React component to render a button that exercises a choice on click.
const ExerciseChoiceButtonBase = (props) => (
<Button
onClick={(e) => {
props.exercise(props.contractId, props.choiceName, props.choiceArgument);
e.stopPropagation();
}}
>
{props.title}
</Button>
)
ExerciseChoiceButtonBase.displayName = 'ExerciseChoiceButtonBase';
// Inject the `exercise` property to the props of the wrapped component.
// The value of that property is a convenience function to send a
// network request to exercise a choice.
const ExerciseChoiceButton = withExercise()(ExerciseChoiceButtonBase)
ExerciseChoiceButton.displayName = 'ExerciseChoiceButton';
Finally, use the following code in your table cell definition:
{
key: "id",
title: "Action",
createCell: ({rowData}) => {
// Render our new component.
// The contract ID and choice argument are computed from the current contract row.
return ({
type: "react",
value: <ExerciseChoiceButton
title='Transfer to issuer'
contractId={rowData.id}
choiceArgument={
DamlLfValue.record(undefined, [
{label: 'newOwner', value: DamlLfValue.party(DamlLfValue.toJSON(rowData.argument).issuer)}
])
}
choiceName='Iou_Transfer'
/>
});
},
sortable: true,
width: 80,
weight: 3,
alignment: "left"
}
Another option would be create a React component where the onClick handler sends a REST API request using fetch(). Inspect the network traffic when exercising a choice through the Navigator UI in order to find out the format of the request.

How can we add a custom dropdown in tiny mce using yii2

I want to add a custom drop down in tiny mce editor, I am using yii framework and using a yii plugin to integrate the editor
You haven't added any details in your question but since you are a new
bee here and SO Code of Conduct
has been revised to be more nice and humble towards newcomers, so I am
adding the answer for you, do go through the How to Ask a
Question? before posting a
question next time.
You can add the dropdown in the TinyMCE using setup option which takes a callback function with a parameter editor which holds the editor instance, and then you need to call the editor.addButton(label, options) with the options to create the custom dropdown button.
As you have not added any details in the question like what are the options that you are going to display in the dropdown so, I will assume here as usernames from the database in the variable $users.
Steps to Implement
First, we will convert $users array to js array by using yii\helpers\Json::encode().
Iterate that array to create the drop-down options with onclick event to insert the content to the editor.
Use editor.addButton('users',options) to create a button of type dropdown with label users to be later used when initializing the editor toolbar buttons.
Add the following code on top of the view
$usersList = \yii\helpers\Json::encode($users);
$tinyMCECallback = <<< JS
function (editor) {
let usersList = $usersList;
let options = [];
//iterate the user array and create the options with text and
//onclick event to insert the content on click to the editor
$.each(usersList, function(label, mapping) {
options.push({
text: label,
onclick: function() { tinymce.activeEditor.insertContent(label); }
});
});
//add the dropdown button to the editor
editor.addButton('users', {
type: 'menubutton',
text: 'Users',
icon: false,
menu: options
});
}
JS;
Now all you need to do is to pass the $tinyMCECallback to the setup option of the tinyMCE widget, if you are using the active form you code should be like below.
Note: Don't forget to add the users label of the button to the toolbar options, or if you change it in the javascript code change it accordingly in the editor toolbar options otherwise it won't show up
<?php
echo $form->field(
$model, 'body'
)->widget(
TinyMce::class, [
'options' => ['rows' => 10],
'language' => 'en',
'clientOptions' => [
'menubar' => false,
'statusbar' => false,
'toolbar' => "undo redo | users",
'setup' => new \yii\web\JsExpression($tinyMCECallback),
],
]
);
?>