Loading external script tag in react component - html

I am building a stock picking application. I found this chart template that is really great, it comes with a html script:
<!-- TradingView Widget BEGIN -->
<div id="tv-medium-widget-b3840"></div>
<script type="text/javascript" src="https://d33t3vvu2t2yu5.cloudfront.net/tv.js"></script>
<script type="text/javascript">
new TradingView.Widget({
"container_id": "tv-medium-widget-b3840",
"symbols": [
[
"Apple",
"AAPL "
],
[
"Google",
"GOOGL"
],
[
"Yahoo!",
"YHOO"
]
],
"gridLineColor": "#e9e9ea",
"fontColor": "#83888D",
"underLineColor": "#dbeffb",
"trendLineColor": "#4bafe9",
"width": 1000,
"height": 350,
"tradeItWidget": false,
"locale": "en"
});
</script>
<!-- TradingView Widget END -->
My question is how would I put it inside of a react component on a react-router route? I just left the script tags in the html and tried calling the constructor inside of a component but it is being rendered on all pages as canvas instead of the one the router points to.
const TradingViews = React.createClass({
componentDidMount:
new TradingView.widget({
"width": 980,
"height": 610,
"symbol": "QUANDL:YAHOO/FUND_FUSEX",
"interval": "M",
"timezone": "Etc/UTC",
"theme": "White",
"style": "1",
"locale": "en",
"toolbar_bg": "#f1f3f6",
"enable_publishing": false,
"allow_symbol_change": true,
"hideideas": true,
"show_popup_button": true,
"popup_width": "1000",
"popup_height": "650"
}),
render:function(){
return(
null
)
}
});
export default TradingViews;

Related

Trading view chart is not taking the whole space of the wrapper div

I want to implement a trading view widget but its not taking the whole space of the wrapper div
I am embedding the chart from this website https://www.tradingview.com/widget/advanced-chart/ and I have selected Autosze
My website: https://finfin.sk/uniswap-recenzia/#uni
Screenshot
CSS
.trading-wrapper {
width: 100%;
height: 500px;
}
This is the code:
<!-- TradingView Widget BEGIN -->
<div class="tradingview-widget-container">
<div id="tradingview_98062"></div>
<div class="tradingview-widget-copyright"><span class="blue-text">UNIUSD Chart</span> by TradingView</div>
<script type="text/javascript" src="https://s3.tradingview.com/tv.js"></script>
<script type="text/javascript">
new TradingView.widget(
{
"autosize": true,
"symbol": "BINANCEUS:UNIUSD",
"interval": "D",
"timezone": "Etc/UTC",
"theme": "dark",
"style": "1",
"locale": "en",
"toolbar_bg": "#f1f3f6",
"enable_publishing": false,
"hide_top_toolbar": true,
"hide_legend": true,
"save_image": false,
"container_id": "tradingview_98062"
}
);
</script>
</div>
<!-- TradingView Widget END -->
I also found the same problem, but after searching I found that the code must add width and height to 100% like this:
new TradingView.widget(
{
"autosize": true,
"width": "100%",
"height": "100%",
"symbol": "OANDA:XAUUSD",
"interval": "D",
"timezone": "America/Argentina/Buenos_Aires",
"theme": "dark",
"style": "1",
"locale": "es",
"toolbar_bg": "#f1f3f6",
"enable_publishing": false,
"allow_symbol_change": true,
"container_id": "tradingview_91540"
}

Why is Leaflet Ajax not processing and displaying GeoJSON data?

I have been trying for weeks to get Leaflet Ajax to accept data requests from the Land Information New Zealand (LINZ) API without success.
I have a valid key (not included in the snippet) and have tried several tests to load this data in. Other datasets from the LINZ API do not worth either.
What am I doing wrong here?
<html>
<head>
<!-- Style -->
<link rel="stylesheet" href="css/style.css">
<!-- Leaflet -->
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.7.1/dist/leaflet.css"
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
crossorigin=""/>
<script src="https://unpkg.com/leaflet#1.7.1/dist/leaflet.js"
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
crossorigin=""></script>
<!-- Leaflet Ajax -->
<script type='text/javascript' src="./js/leaflet.ajax.js"></script>
<div id="map"></div>
</head>
<body>
<script>
map = L.map('map').setView([-41.29132, 174.77931],16)
var OpenTopoMap = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', {
maxZoom: 17,
attribution: 'Map data: © OpenStreetMap contributors, SRTM | Map style: © OpenTopoMap (CC-BY-SA)'
});
OpenTopoMap.addTo(map)
property_tiles_link = "https://data.linz.govt.nz/services/query/v1/vector.json?key=KEY_GOES_HERE&layer=50804&x=172.61706383056807&y=-43.57379489129212&max_results=3&radius=10000&geometry=true&with_field_names=true"
geojson = new L.GeoJSON.AJAX(property_tiles_link).addTo(map)
console.log(geojson)
overlays = {
"geojson": geojson
}
basemaps = {
"OpenTopoMap": OpenTopoMap
}
L.control.layers(basemaps, overlays).addTo(map)
</script>
</body>
The code snippet results in this output:
Looking through the logged GeoJSON object does not seem to show any successfully parsed data. The error message in Firefox translates roughly to "The configuration of HTML characters hasn't been declared. The document will show 'rubbish' text in some configurations of the browser."
Any ideas would be super helpful!
An example of the response:
{
"vectorQuery": {
"layers": {
"50804": {
"crs": {
"type": "name",
"properties": {
"name": "EPSG:4326"
}
},
"field_names": ["id", "title_no", "status", "type", "land_district", "issue_date", "guarantee_status", "estate_description", "number_owners", "spatial_extents_shared"],
"type": "FeatureCollection",
"features": [{
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[175.4776337167, -41.2221699],
[175.4782420833, -41.2225527833],
[175.4801549333, -41.2237566167],
[175.476269, -41.2259343],
[175.47357595, -41.22444375],
[175.4776337167, -41.2221699]
]
]
]
},
"distance": 0,
"type": "Feature",
"properties": {
"id": 1468560,
"title_no": "WN53B/277",
"status": "LIVE",
"type": "Freehold",
"land_district": "Wellington",
"issue_date": "1998-04-16 00:00:00",
"guarantee_status": "Guarantee",
"estate_description": "Fee Simple, 1/1, Lot 1 Deposited Plan 85426, 110,945 m2",
"number_owners": 1,
"spatial_extents_shared": false
},
"id": 1191838
}, {
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[175.48005638330002, -41.2282570333],
[175.48105425000003, -41.2286012667],
[175.4789359, -41.2297867333],
[175.47874645, -41.2298923],
[175.4767530167, -41.2310074667],
[175.47604405, -41.2314040667],
[175.47550265, -41.23170695000001],
[175.4749415833, -41.2320208833],
[175.4745023167, -41.2322666333],
[175.474015, -41.2317699833],
[175.4735909, -41.23133785000001],
[175.4735833, -41.2313303667],
[175.4732046667, -41.23094425],
[175.4728425667, -41.2305752833],
[175.4725057833, -41.2302328833],
[175.4722412333, -41.2299625],
[175.4719444667, -41.2296600833],
[175.4715930333, -41.22930195],
[175.47127355, -41.2289763667],
[175.4712437333, -41.2289459833],
[175.4708617, -41.22855675],
[175.4704157833, -41.2281024167],
[175.4699766167, -41.227654983300006],
[175.4692410167, -41.2269055],
[175.4692395833, -41.2269040667],
[175.46921793330003, -41.2268834667],
[175.4718439333, -41.2254143333],
[175.4733724167, -41.2245578167],
[175.48005638330002, -41.2282570333]
]
]
]
},
"distance": 134,
"type": "Feature",
"properties": {
"id": 2348803,
"title_no": "WN103/58",
"status": "LIVE",
"type": "Freehold",
"land_district": "Wellington",
"issue_date": "1899-10-23 00:00:00",
"guarantee_status": "Guarantee",
"estate_description": "Fee Simple, 1/1, Lot 75 Deposited Plan 579, 409,390 m2",
"number_owners": 1,
"spatial_extents_shared": true
},
"id": 5113879
}, {
"geometry": {
"type": "MultiPolygon",
"coordinates": [
[
[
[175.48005638330002, -41.2282570333],
[175.48105425000003, -41.2286012667],
[175.4789359, -41.2297867333],
[175.47874645, -41.2298923],
[175.4767530167, -41.2310074667],
[175.47604405, -41.2314040667],
[175.47550265, -41.23170695000001],
[175.4749415833, -41.2320208833],
[175.4745023167, -41.2322666333],
[175.474015, -41.2317699833],
[175.4735909, -41.23133785000001],
[175.4735833, -41.2313303667],
[175.4732046667, -41.23094425],
[175.4728425667, -41.2305752833],
[175.4725057833, -41.2302328833],
[175.4722412333, -41.2299625],
[175.4719444667, -41.2296600833],
[175.4715930333, -41.22930195],
[175.47127355, -41.2289763667],
[175.4712437333, -41.2289459833],
[175.4708617, -41.22855675],
[175.4704157833, -41.2281024167],
[175.4699766167, -41.227654983300006],
[175.4692410167, -41.2269055],
[175.4692395833, -41.2269040667],
[175.46921793330003, -41.2268834667],
[175.4718439333, -41.2254143333],
[175.4733724167, -41.2245578167],
[175.48005638330002, -41.2282570333]
]
]
]
},
"distance": 134,
"type": "Feature",
"properties": {
"id": 4177014,
"title_no": "94991",
"status": "LIVE",
"type": "Leasehold",
"land_district": "Wellington",
"issue_date": "2003-06-10 09:00:00",
"guarantee_status": "Guarantee",
"estate_description": "Leasehold, 1/1, Lot 75 Deposited Plan 579, 409,390 m2",
"number_owners": 1,
"spatial_extents_shared": true
},
"id": 5116291
}]
}
}
}
}
The Leaflet-ajax plugin expects directly a GeoJSON compliant object in the loaded data, whereas in the sample response you show, the structure of the response is:
{
"vectorQuery": {
"layers": {
[layerId]: {
// GeoJSON FeatureCollection
}
}
}
}
Therefore you have to convert this data into a GeoJSON object first. Here in this case it looks quite simple, as you just have to extract the FeatureCollection. You can use leaflet-ajax middleware option to perform this conversion between the reception of the data and before it is processed to be transformed into Leaflet layers:
new L.GeoJSON.AJAX("url", {
middleware(rawData) {
// Extract the GeoJSON FeatureCollection
const layerId = 50804;
return rawData.vectorQuery.layers[layerId];
}
});

BotFramework-WebChat - Adaptive Card

Is there a way to add Onchange event to the adaptive card input field that is rendered in webchat (version V4). Example changing a quantity value (Adaptive card inputfield of type number) in the checkout screen should update the Total value (Adaptive card text field)
To keep it simple....In the below image once i change the number in the input box it should update in the below text box. everything should happen on the webchat V4(React) client side
Below are the options i tried, don't have any code to submit here:
option1: Tried to add an event to quantity input field in the card coming from the bot using middleware but not able to find an option to uniquely identify the input field to add the event (can see multiple input fields based on no of items in the card)
option2: create a new card in the frontend based on the card coming from bot and add events to that new card. Is it possible to interrupt the message going to bot and send a card from the frontend ?
option3: add an update button to the card so that the total is calculated in the backend and a update card is submitted to the user
below is the payload:
{
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0",
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"text": "Output",
"weight": "Bolder",
"horizontalAlignment": "Center",
"size": "Large",
"id": "output",
"color": "Good"
},
{
"type": "Container",
"items": [
{
"$data": "{items}",
"type": "Container",
"items": [
{
"type": "TextBlock",
"text": " ",
"id": "line",
"spacing": "None"
},
{
"type": "Image",
"altText": "",
"id": "myimage",
"url": "{imgUrl}",
"spacing": "None",
"size": "Stretch",
"width": "1000px",
"height": "100px"
},
{
"type": "ColumnSet",
"id": "imgset",
"columns": [
{
"type": "Column",
"width": 50,
"id": "desc",
"items": [
{
"type": "TextBlock",
"text": "{description}",
"weight": "Bolder",
"spacing": "None",
"id": "desc",
"wrap": true,
"maxLines": 4
}
],
"spacing": "None"
}
],
"spacing": "None"
},
{
"type": "ColumnSet",
"spacing": "None",
"columns": [
{
"type": "Column",
"width": 50,
"id": "qty",
"items": [
{
"type": "Input.Number",
"placeholder": "Quantity",
"id": "myquantity",
"min": 0,
"max": 100,
"value": "{quantity}",
"spacing": "None"
}
],
"horizontalAlignment": "Left",
"verticalContentAlignment": "Center",
"spacing": "None"
},
{
"type": "Column",
"id": "pricec",
"items": [
{
"type": "TextBlock",
"text": "{price}",
"id": "pricet",
"horizontalAlignment": "Right",
"spacing": "None"
}
],
"verticalContentAlignment": "Center",
"horizontalAlignment": "Right",
"width": 50,
"spacing": "None"
}
],
"id": "qtypset"
},
{
"type": "ColumnSet",
"spacing": "None",
"columns": [
{
"type": "Column",
"width": 1,
"items": [
{
"type": "TextBlock",
"text": "Sub Total",
"size": "Medium",
"id": "subtotal00",
"weight": "Bolder",
"spacing": "None"
}
],
"id": "subtotal1",
"spacing": "None"
},
{
"type": "Column",
"width": 1,
"items": [
{
"type": "TextBlock",
"horizontalAlignment": "Right",
"text": "{subtotal}",
"size": "Medium",
"weight": "Bolder",
"id": "subtotalt0",
"color": "Accent",
"spacing": "None"
}
],
"id": "subtotal200",
"spacing": "None"
}
],
"id": "colsetsubtot00"
}
],
"id": "itemcontainer",
"style": "emphasis",
"spacing": "None"
}
],
"id": "rootcontainer",
"style": "accent"
},
{
"type": "ColumnSet",
"id": "totalset",
"columns": [
{
"type": "Column",
"width": 50,
"id": "totalcolumn",
"items": [
{
"type": "TextBlock",
"text": "Total",
"size": "Medium",
"isSubtle": true,
"weight": "Bolder",
"id": "total",
"color": "Dark"
}
]
},
{
"type": "Column",
"width": 50,
"items": [
{
"type": "TextBlock",
"text": "{total}",
"size": "Medium",
"id": "totaltext",
"horizontalAlignment": "Right",
"weight": "Bolder",
"color": "Accent"
}
],
"id": "totalcol2"
}
]
}
],
"id": "final"
}
I am using the below example as a starting point
https://github.com/microsoft/BotFramework-WebChat/tree/master/samples/04.api/e.piping-to-redux
webchat.js:
import React from 'react';
import ReactWebChat, { createDirectLine, createStore } from 'botframework-webchat';
import directLineDisconnect from 'botframework-webchat-core/lib/actions/disconnect';
import dispatchIncomingActivityMiddleware from './dispatchIncomingActivityMiddleware';
import uuid from 'uuid';
export default class extends React.Component {
constructor(props) {
super(props);
this.store = createStore({}, dispatchIncomingActivityMiddleware(props.appDispatch, this));
this.activityMiddleware = this.setActivityMiddleware();
this.attachmentMiddleware = this.setAttachmentMiddleware();
this.state = {};
}
componentDidMount() {
this.fetchToken();
this.setSendBox();
}
componentWillUnmount(){
}
async fetchToken() {
const myHeaders = new Headers();
const userDetails = uuid.v4();
myHeaders.append('Authorization', 'Bearer ' + 'mytoken');
myHeaders.append('Content-type', 'application/json');
const res = await fetch('https://directline.botframework.com/v3/directline/tokens/generate', {
body: JSON.stringify({ user: { id: userDetails, name: userDetails }}),
method: 'POST', headers: myHeaders });
const { token } = await res.json();
console.log("My Token: " + token);
this.setState(() => ({
directLine: createDirectLine({ token })
}));
}
setActivityMiddleware(){
return () => next => card => {
return children => (
<div
className={card.activity.attachments && (card.activity.attachments[0].content.id === "output") ? card.activity.attachments && card.activity.attachments[0].content.id : ''}
>
{next(card)(children)}
</div>
);
};
}
setAttachmentMiddleware(){
return () => next => ({ card, activity, attachment: baseAttachment }) => {
let attachment = baseAttachment;
if (baseAttachment.content.body){
switch (baseAttachment.content.body[0].id) {
case 'review':
for (let i = 0; i < attachment.content.body[1].items.length; i++) {
attachment.content.body[1].items[i].items[3].columns[0].items[0].value = baseAttachment.content.body[1].items[i].items[3].columns[0].items[0].value.toString();
} //for loop
break;
default:
break;
}
}
return next({ card, activity, attachment });
};
}
setSendBox() {
this.store.dispatch({
type: 'WEB_CHAT/SET_SEND_BOX',
payload: { text: 'sample:redux-middleware' }
});
/*
this.store.dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: { name: 'membersAdded',
value: { language: window.navigator.language }
}
}); */
}
render() {
return this.state.directLine ? (
<ReactWebChat
activityMiddleware={this.activityMiddleware}
attachmentMiddleware={this.attachmentMiddleware}
directLine={this.state.directLine}
store={this.store}
styleOptions={{
backgroundColor: 'Transparent',
hideUploadButton: true
}}
/>
) : (
<div>Connecting to bot…</div>
);
}
}
dispatchIncomingActivityMiddleware.js:
export default function(dispatch, thisvariable) {
return () => next => action => {
if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY') {
const { activity } = action.payload;
if (activity.from.role === 'bot'){
var inputBox=document.getElementsByClassName("css-eycyw2");
if (inputBox.length > 0){
inputBox[inputBox.length - 1].style.display='block';
}
}
}
if ((action.type === 'WEB_CHAT/SEND_POST_BACK') || (action.type === 'WEB_CHAT/SEND_MESSAGE')) {
var inputBox=document.getElementsByClassName("css-eycyw2");
if (inputBox.length > 0){
inputBox[inputBox.length - 1].style.display='none';
dispatch(setInputVisibility(true));
}
}
return next(action);
};
}
The first thing to understand is that Web Chat uses the Adaptive Cards JavaScript SDK, available as an npm package. Web Chat mostly uses the out-of-the-box rendering functionality of the SDK, but one important thing it changes is how actions are handled. Without providing a customized handler, submit actions wouldn't be sent to the bot.
adaptiveCard.onExecuteAction = handleExecuteAction;
This is how applications are supposed to use Adaptive Cards. While most of the functionality is handled on the SDK side, there are a few things the application needs to do to make Adaptive Cards work for that specific app. While you can see Web Chat assigning a function to the onExecuteAction "event" property of a specific Adaptive Card instance, there is also a static counterpart of onExecuteAction that could be accessed like this:
AdaptiveCard.onExecuteAction = handleExecuteAction;
Using the static event will apply a handler for all Adaptive Cards instead of just one, but it will be overridden by any handlers applied to specific instances. The reason I'm telling you this is because there are many more static events, and there are a few in particular that will be useful for your situation:
static onAnchorClicked: (element: CardElement, anchor: HTMLAnchorElement) => boolean = null;
static onExecuteAction: (action: Action) => void = null;
static onElementVisibilityChanged: (element: CardElement) => void = null;
static onImageLoaded: (image: Image) => void = null;
static onInlineCardExpanded: (action: ShowCardAction, isExpanded: boolean) => void = null;
static onInputValueChanged: (input: Input) => void = null;
static onParseElement: (element: CardElement, json: any, errors?: Array<HostConfig.IValidationError>) => void = null;
static onParseAction: (element: Action, json: any, errors?: Array<HostConfig.IValidationError>) => void = null;
static onParseError: (error: HostConfig.IValidationError) => void = null;
static onProcessMarkdown: (text: string, result: IMarkdownProcessingResult) => void = null;
It would be possible for you to come up with a solution that uses the onInputValueChanged event, which fires every time any input in the card is changed. Your handler could search the card for other elements that it needs to use as operands for its calculation, and it would also need to search the card for the element that would display the result. Rather than doing all that work every time a character is typed, I prefer a solution that searches the card just once at the beginning for the elements it will use in its calculation. An alternative to listening to events on the Adaptive Card class or an Adaptive Card instance is to listen to events on particular elements, like inputs. So my example will use the static onParseElement event to get the elements it needs and then use the onValueChanged event for specific input instances it finds.
Before writing the code for the handler, we need to come up with a way for the code to know which elements to use for the operands and result of the calculation. For example, you could just have the code combine every input in the card (or in a container) and put the result in the last text block found. For my example, I've come up with a naming schema that the code can use. There are two keywords, "total" and "price", and the code looks for them in each element ID. I want to make it clear that this schema is totally arbitrary and that you can do something different if you want. Here's my example card:
{
"type": "AdaptiveCard",
"version": "1.0",
"body": [
{
"type": "TextBlock",
"text": "$10.00",
"id": "foo_a_price"
},
{
"type": "Input.Text",
"id": "foo_a"
},
{
"type": "TextBlock",
"text": "$2.00",
"id": "foo_b_price"
},
{
"type": "Input.Text",
"id": "foo_b"
},
{
"type": "TextBlock",
"text": "total",
"id": "total_foo"
}
],
"actions": [
{
"type": "Action.Submit",
"title": "Submit"
}
]
}
You might be able to guess from looking at this that the idea is for one text block to have an ID that starts with "total_" and has some identifier after it. The quantities you want to add up start with that same identifier, and the price you want to multiply with each quantity has the same ID as the quantity but with the suffix "_price". I recommend using number inputs instead of text inputs, but this example shows that text still works. And here is the code for my example app that reads the schema:
import * as adaptiveCardsPackage from 'adaptivecards';
adaptiveCardsPackage.AdaptiveCard.onParseElement = element => {
const PREFIX_TOTAL = 'total_';
const SUFFIX_PRICE = '_price';
if (element.id && element.id.startsWith(PREFIX_TOTAL)) {
const itemPrefix = element.id.slice(PREFIX_TOTAL.length);
const card = element.getRootElement();
const inputs = card.getAllInputs().filter(input => input.id.startsWith(itemPrefix));
const products = {};
for (const input of inputs) {
const priceElement = card.getElementById(input.id + SUFFIX_PRICE);
const price = Number(priceElement.text.replace(/[^0-9.-]+/g, '')) || 0;
// `sender` will be the same as `input`.
// You could capture the input const instead of using the argument,
// but I'm demonstrating that you don't need to.
input.onValueChanged = sender => {
const quantity = Number(sender.value) || 0;
products[sender.id] = price * quantity;
const sum = Object.values(products).reduce((a, b) => a + b);
element.setText("$" + sum.toFixed(2));
element.renderedElement.replaceWith(element.render());
};
}
}
};
I have reason to believe that this change to the AdaptiveCard class will automatically be applied to the AdaptiveCard class in the package that Web Chat imports, since it's the same class in the same package. However, Web Chat now allows you to provide your own Adaptive Cards package as a property, so you can make sure Web Chat is using the package with your special event handler:
<ReactWebChat
directLine={createDirectLine({secretOrToken})}
adaptiveCardsPackage={adaptiveCardsPackage}
/>

Loading pushpin in the forge viewer does not respect the viewerState

We are using the "Autodesk.BIM360.Extension.PushPin" extension inside the forge viewer to enable push pins.
When a push pin has been added to the model, we serialize the pushpin data and store it in our database. An example of such a pushpin is here:
{
"id": "12",
"label": "12",
"status": "quality_issues-not_approved",
"position": {
"x": 15.324803588519861,
"y": -10.150864635427533,
"z": -5.532972775562976
},
"type": "issues",
"objectId": 24518,
"externalId": "d9a1e318-14d0-4d08-b7ab-6d1c331454c2-002793d1",
"viewerState": {
"seedURN": "dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6MDQyY2QwMmUtNzU0Yi00ZDY2LTgyYTMtNjBmYjFlOWVjMjcxL2U5ODAxZTA4LTUwZjQtNDc0ZS05ZWU4LTAxYWQ0ZGM0ODFiYl9WMV9Lb25nZXN0aWVuKzMwKy0rVGlsYnlnbmluZystK0clMjVDMyUyNUE2bGRlbmRlK2QuKzA1LjA2LnJ2dA",
"objectSet": [{
"id": [],
"isolated": [],
"hidden": [],
"explodeScale": 0,
"idType": "lmv"
}],
"viewport": {
"name": "",
"eye": ["-15.17842530349136", "-0.9048862425583284", "0.6506974303790392"],
"target": ["-22.06049144652811", "0.915848677106827", "-0.4205110420886964"],
"up": [-0.14385076361076257, 0.038057482024001874, 0.9888673247056924],
"worldUpVector": [0, 0, 1],
"pivotPoint": ["-22.510046835506888", "1.6223793651751013", "3.668585646439837"],
"distanceToOrbit": 7.198985875545766,
"aspectRatio": 1.491792224702381,
"projection": "orthographic",
"isOrthographic": true,
"orthographicHeight": 7.198985875545767
},
"renderOptions": {
"environment": "Boardwalk",
"ambientOcclusion": {
"enabled": true,
"radius": 13.123359580052492,
"intensity": 1
},
"toneMap": {
"method": 1,
"exposure": -7,
"lightMultiplier": -1e-20
},
"appearance": {
"ghostHidden": true,
"ambientShadow": true,
"antiAliasing": true,
"progressiveDisplay": true,
"swapBlackAndWhite": false,
"displayLines": true,
"displayPoints": true
}
},
"cutplanes": [],
"globalOffset": {
"x": -20.808594999999997,
"y": 6.686511499999999,
"z": 8.456207
}
},
"objectData": {
"guid": "6de5f80c-73da-30ae-b2d1-8a78f177c2a4",
"urn": "dXJuOmFkc2sub2JqZWN0czpvcy5vYmplY3Q6MDQyY2QwMmUtNzU0Yi00ZDY2LTgyYTMtNjBmYjFlOWVjMjcxL2U5ODAxZTA4LTUwZjQtNDc0ZS05ZWU4LTAxYWQ0ZGM0ODFiYl9WMV9Lb25nZXN0aWVuKzMwKy0rVGlsYnlnbmluZystK0clMjVDMyUyNUE2bGRlbmRlK2QuKzA1LjA2LnJ2dA",
"viewableId": "aaff5911-e8b1-4ae2-b41c-4284d0703eb4-00150218",
"viewName": "{3D}"
}
}
We then load the pushpin into the model again at a later point (when the user reopens the model), like this:
pushPinExtension.loadItems([pushPinItem]);
The result is that the pushpin is added in the model at the correct place, but the viewer state is incorrect. It seems like the viewer state for the pushpin is set to the viewer state of the model at the time when we load the pushpin - and not to the viewer state stored inside the pushpin.
Is this expected behaviour? - and if so, how do I use the viewer state from the pushpin instead?
why not explicitly load the viewer state stored in the pushpin separately after loading the pushpin:
pushPinExtension.loadItems([pushPinItem]);
viewer.restoreState(pushPinItem.viewerState)
EDIT:
Try restore the viewer state when an item is clicked - subscribe to the click event with:
viewer.restoreState(...)
//...
})

Backstopjs site loading issue not solved by delay: what is wrong?

When I try to run backstopjs on certain sites (they all must have some dynamic rendering thing in common, though I don't know what), the screenshots generated by backstopjs only include the first piece of content, centered in the screen. Here's the URL to a screenshot: https://user-images.githubusercontent.com/41495147/63806833-1612b680-c8e2-11e9-9932-680864b470b7.png
I've already tried setting the delay to 5 seconds. I've tried waiting until the footer class is available before screenshot. No dice. What is going on? Here's my config file:
"id": "backstop_default",
"viewports": [
{
"label": "phone",
"width": 320,
"height": 480
},
{
"label": "tablet",
"width": 1024,
"height": 768
},
{
"label": "desktop",
"width": 1280,
"height": 1024
}
],
"onBeforeScript": "puppet/onBefore.js",
"onReadyScript": "puppet/onReady.js",
"scenarios": [
{
"label": "VMLYR Home",
"cookiePath": "backstop_data/engine_scripts/cookies.json",
"url": "https://www.vmlyr.com",
"referenceUrl": "",
"readyEvent": "",
"readySelector": ".region-footer",
"delay": 5000,
"hideSelectors": [],
"removeSelectors": [],
"hoverSelector": "",
"clickSelector": "",
"postInteractionWait": 0,
"selectors": [],
"selectorExpansion": true,
"expect": 0,
"misMatchThreshold" : 0.1,
"requireSameDimensions": true
}
],
"paths": {
"bitmaps_reference": "backstop_data/bitmaps_reference",
"bitmaps_test": "backstop_data/bitmaps_test",
"engine_scripts": "backstop_data/engine_scripts",
"html_report": "backstop_data/html_report",
"ci_report": "backstop_data/ci_report"
},
"report": ["browser"],
"engine": "puppeteer",
"engineOptions": {
"args": ["--no-sandbox"]
},
"asyncCaptureLimit": 5,
"asyncCompareLimit": 50,
"debug": false,
"debugWindow": false
}```