Ionic - for loop for rect in svg - ionic-framework

I recently started using IONIC, SoThe problem I have, is for me very difficult to put in words. Please bear with me.
I'm trying something with svg's within it clickable rectangles. I have to do this multiple times, so instead of putting everything in the HTML file, I thought of using an external JSON file,in it are array's with the x&y values and a string. So that I can keep the HTML file 'clean'.
Anyhow the problem is that, I want to loop the rect element for the clickable rectangels.
This is the Json file with the array in it
[
{"x": "375", "y": "7", "string": "steiger"},
{"x": "459", "y": "60", "string": "kanaal"},
{"x": "130", "y": "197", "string": "Westkolk"},
{"x": "510", "y": "140", "string": "Sluizencomplex"},
{"x": "492", "y": "237", "string": "wachthaven"},
{"x": "510", "y": "285", "string": "autosteiger"},
{"x": "578", "y": "335", "string": "Zwaaikom"},
{"x": "505", "y": "630", "string": "Scheidingsboei"},
{"x": "705", "y": "530", "string": "radartoren"},
{"x": "925", "y": "350", "string": "Kilometerraai"},
{"x": "880", "y": "295", "string": "schip"},
{"x": "950", "y": "160", "string": "tunnel"}
]
Here is the part with the SVG's, where im trying to loop the rectangles.
<svg viewBox="0 0 1280 700">
<image width="1280" height="700" xlink:href="assets/imgs/maps/samenwerkenopdecorridor/opdracht1.svg">
</image>
<rect *ngFor="let item of coordinaten" x="{{item.x}}" y="7" width="200" height="45" fill="#fff" opacity="0.5" (click)="clickOnArea('Steiger')"
/>
I tried to put the *ngFor loop in the rect element, than in the X attribute.
Error: Template parse errors: Can't bind to 'x' since it isn't a known property of ':svg:rect'. (" </image> <rect *ngFor="let item of coordinaten" [ERROR ->]x="{{item.x}}" y="7" width="200" height="45" fill="#fff" opacity="0.5" (click)="clickOnArea('Steiger'"): ng:///AppModule/MapPage.html#49:43
I got this error. I tried to put a div around de rect element to put the ngFor in the div, but that is also wrong. Please if somebody knows a solution or even if this possible. that would be a great help !

SVG needs special treatment in Angular 2+, read more here: https://teropa.info/blog/2016/12/12/graphics-in-angular-2.html
Now as for your example, you should do something like this:
<svg viewBox="0 0 1280 700">
<svg:image width="1280" height="700" xlink:href="assets/imgs/maps/samenwerkenopdecorridor/opdracht1.svg">
</svg:image>
<svg:rect *ngFor="let item of coordinaten" [attr.x]="item.x" [attr.y]="7" width="200" height="45" fill="#fff" opacity="0.5" (click)="clickOnArea('Steiger')"
/>
Basically anything except for main svg node should have "svg" pre-tag and all the attributes bindings should have [attr.xyz]:
<svg:path [attr.xyz]=""></svg:path> etc

Related

How to parse dynamic json?

I'm new to flutter development, I can't figure out how to parse json correctly, since lists are changeable.
Maybe there are some libraries that allow you to turn json into an object right away?
{
"name": "Nuan",
"key": "wqewewrwerer",
"places": {
"1": {
"place": 1,
"numberPlaces": 4,
"type": "TABLE"
},
"2": {
"place": 2,
"numberPlaces": 4,
"type": "TABLE"
},
"3": {
"place": 3,
"numberPlaces": 4,
"type": "TABLE"
}
},
"menu": {
"categories": [{
"name": "Salads",
"elements": [{
"id": 1,
"name": "Caesar salad",
"img": "cesar.jpg",
"price": 4,
"currency": "USD",
"weight": "222",
"typeWeight": "g",
"time": 3,
"calories": 500,
"description": "The salad\u0027s creation is generally attributed to the restaurateur Caesar Cardini, an Italian immigrant who operated restaurants in Mexico and the United States. His daughter Rosa recounted that her father invented the salad at his Prohibition-era restaurant in Tijuana, Mexico when a Fourth of July rush in 1924 depleted the kitchen\u0027s supplies. (Cardini lived in San Diego but ran the family restaurant in Tijuana to attract American customers seeking to circumvent the restrictions of the Prohibition). Cardini made do with what he had, adding the dramatic flair of the table-side tossing \"by the chef.\" A number of Cardini\u0027s staff have said that they invented the dish.",
"structure": "croutons, romaine, anchovies, parmeasan cheese, olive oil, vinegar and plenty of black pepper."
}, {
"id": 2,
"name": "Greek salad",
"img": "grek.jpg",
"price": 5,
"currency": "USD",
"weight": "220",
"typeWeight": "g",
"time": 3,
"calories": 300,
"description": "Various other salads have also been called \"Greek\" in the English language in the last century, including some with no apparent connection to Greek cuisine. A 1925 Australian newspaper described a Greek salad of boiled squash dressed with sour milk; a 1934 American newspaper described a mayonnaise-dressed lettuce salad with shredded cabbage and carrots",
"structure": "Lettuce, tomatoes, feta, olives, cucumber"
}, {
"id": 3,
"name": "Salmon salad",
"img": "semga.jpg",
"price": 8,
"currency": "USD",
"weight": "250",
"typeWeight": "g",
"time": 3,
"calories": 400
}, {
"id": 4,
"name": "Hunting salad",
"img": "hunting.jpg",
"price": 7,
"currency": "USD",
"weight": "220",
"typeWeight": "g",
"time": 4,
"calories": 390,
"description": "Hunting salad has such a name, since it includes meat of animals caught by hunters. History is silent at what point the game meat was replaced with beef, hunting sausages or even pork, but in our reality it is these meat products that are used for such a salad. The salad turns out to be very satisfying, nutritious and quite dense � ideal for men\u0027s snacks.",
"structure": "sausages, potatoes, greens"
}]
}, {
"name": "soups",
"elements": [{
"id": 5,
"name": "Solyanka soup",
"img": "solyanka.jpg",
"price": 10,
"currency": "USD",
"weight": "300",
"typeWeight": "g",
"time": 15,
"calories": 300,
"description": "There is no consensus on the correctness of the name selyanka in relation to soup. Russian linguist and writer L. I. Skvortsov writes about the traditionality of the name selyanka and the ambiguity of the etymology of the word \"solyanka\", at the same time, Russian historian, researcher and popularizer of cooking V. V. Pokhlebkin writes about the incorrectness and distortion of the name selyanka and claims that the name solyanka is fixed in the \"House-building\" of 1547, while the term selyanka took root only in the XIX century and at the beginning of the XX century was again replaced by the term solyanka. The Dictionary of the Russian Academy (1794) indicated the name solyanka as the main variant, and marked the selyanka variant as \"simple\"",
"structure": "sausage, potato, onion, tomato, pickle"
}, {
"id": 6,
"name": "Borsch soup",
"img": "borsch.jpg",
"price": 8,
"currency": "USD",
"weight": "300",
"typeWeight": "g",
"time": 15,
"calories": 300,
"description": "In the old days, borscht was called soup made from borscht. Later borscht was cooked on beet kvass: it was diluted with water, the mixture was poured into a clay pot or cast iron and brought to a boil. Chopped beets, cabbage, carrots and other vegetables were put in boiling water and put the pot in the oven. The cooked borscht was salted and refilled",
"structure": "meat, carrots, onions, potatoes, beets, white cabbage, beans, tomato paste, vegetable oil, bay leaf, sugar, vinegar"
}, {
"id": 7,
"name": "Mushroom soup",
"img": "mushroom.jpg",
"price": 10,
"currency": "USD",
"weight": "230",
"typeWeight": "g",
"time": 16,
"calories": 320,
"description": "Cream soup with mushrooms has been prepared since about the 17th century, when entrepreneurs already learned how to grow champignons in artificial conditions. It was in France, so this country is considered the birthplace of mushroom soups-puree. But the soup with dried porcini mushrooms is cooked on water and already only one aroma, spreading around the house, can drive even the most refined gourmets crazy.",
"structure": "potatoes, onions, herbs, salt, pepper, vegetable oil, mushrooms, soft processed cheese"
}]
}, {
"elements": [{
"id": 8,
"name": "Crackers",
"img": "crackers.png",
"price": 4,
"currency": "USD",
"weight": "200",
"typeWeight": "g",
"time": 12,
"calories": 600,
"description": "Crackers are second-baked bread, \"dried for the purpose of either storage or further culinary use in various dishes,\" is the definition of the product given by William Pohlebkin (1923-2000), a Russian historian and writer. The main distinguishing feature of crackers from all other bakery products is their reduced humidity, ideally no more than forty-nine percent, more often - up to eight.",
"structure": "bread, garlic, salt, oil"
}, {
"id": 9,
"name": "Croutons",
"img": "croutons.png",
"price": 4,
"currency": "USD",
"weight": "200",
"typeWeight": "g",
"time": 12,
"calories": 580,
"description": "Croutons are made from any bread and are used as a light snack, for example, croutons with garlic for beer, or as an ingredient in soups, broths, salads (\"Caesar\"), cutlets and other dishes. To add to soups (French onion soup), bread is simply fried with salt and/or black pepper.",
"structure": "white bread, garlic, salt, pepper, oil"
}, {
"id": 11,
"name": "Chips",
"img": "chips.png",
"price": 3,
"currency": "USD",
"weight": "100",
"typeWeight": "g",
"time": 3,
"calories": 330,
"structure": "potatoes, salt, pepper, oil"
}]
}]
},
"description": "There are many things in the world, friend Horatio, that our wise men never dreamed of"
}
I've seen standard ways where data is passed to the constructor, but it's not entirely clear how to embed large json there
You can use the json2Dart utility to generate your dart objects and call the fromJson() method on your root object :)

Why doesn't this pymongo subdocument find work?

I'm looking at using mongodb and so far most things that I've tried work. But I don't know why this find doesn't work.
col = db.create_collection("test")
x = col.insert_many([
{"item": "journal", "qty": 25, "size": {"h": 14, "w": 21, "uom": "cm"}, "status": "A"},
{"item": "notebook", "qty": 50, "size": {"h": 8.5, "w": 11, "uom": "in"}, "status": "A"},
{"item": "paper", "qty": 100, "size": {"h": 8.5, "w": 11, "uom": "in"}, "status": "D"},
{"item": "planner", "qty": 75, "size": {"h": 22.85, "w": 30, "uom": "cm"}, "status": "D"},
{"item": "postcard", "qty": 45, "size": {"h": 10, "w": 15.25, "uom": "cm"}, "status": "A"}
])
cursor = col.find({"size": {"h": 14, "w": 21, "uom": "cm"}})
if cursor.retrieved == 0:
print("found nothing") # <<<<<<<<< prints this
As explained into docs into section Match an Embedded/Nested Document:
Equality matches on the whole embedded document require an exact match of the specified document, including the field order.
So, you have to set the object into find stage in the same order that exists into DB.
I really don't know if keys into objects follows an strict order (alphabetically or whatever) but using this query almost everything output the result. Not always so I think there is a "random" (or not possible to handle) concept to store data -at least into mongo playground-.
By the way, the correct way to ensure results is to use dot notation so this query will always works ok.
coll.find({
"size.h": 14,
"size.w": 21,
"size.uom": "cm"
})
I was thinking that cursor.retrieved was non zero if it found something. I guess not. I found that this works:
lst = list(cursor)
print(lst)
cursor.rewind()
print(list(cursor))
if len(lst) != 0:
for d in lst:
print(d)

Is it possible to change width a row in Grafana?

I wanna change width a row in Grafana v5.4.0.
like this screen ...
I'm trying to change JSON Model...
"collapsed": false,
"gridPos": {
"h": 1,
"w": 18,
"x": 0,
"y": 14
},
"id": 12,
"panels": [],
"title": "row2",
"type": "row"
I modified 'w'value from 24 to 18.
'Save changes' is is Succeed.
But, Actually not changed.
unfortunately the row size cannot be changed. Rows are always 12 units wide.
Check these docs: https://docs.huihoo.com/grafana/2.6/guides/basic_concepts/index.html

Filtering on Nested Aggregation Binding

I want to be able to apply a filter to a nested aggregation binding, but it doesn't seem to work. Here is the XML:
<l:Grid id="test" defaultSpan="L6 M6 S6" content="{path : 'test>/', templateShareable:false}">
<l:content>
<VBox width="100%">
<HBox height="100px" alignItems="Center" justifyContent="Start">
<VBox alignItems="Center" width="25%">
<core:Icon src="{test>icon}" width="100%" />
<Text text="{test>text}" width="100%"/>
</VBox>
<VBox id="test" height="80px" items="{path: 'test>data/', templateShareable:false}">
<Link text="{parts: [{ path: 'test>key'},
{ path: 'test>value' }],
formatter : 'dostuff'}"/>
</VBox>
</HBox>
</VBox>
</l:content>
</l:Grid>
And my JSON data is as follows:
{
"results": [{
"text": "object1",
"icon": "icon1",
"data": [{
"value1": "foo",
"value2": "bar"
}, {
"value1": "john",
"value2": "smith"
}]
},
{
"text": "object2",
"icon": "icon2",
"data": [{
"value1": "adam",
"value2": "bobson"
}, {
"value1": "john",
"value2": "smith"
}, {
"value1": "whatever",
"value2": "work please"
}]
}
]
}
I want to be able to filter on test>/results/[n]/data/[n]/[value1 + value2] and have the gird filtered at that level. Whatever I try, it only filters on the Grid content because I can't seem to get the binding for the in VBox "test".
Cheers,
James
Are you trying to filter the content dynamically from JS? Or statically from the XML directly? I assume that you want to do it from JS.
Your VBox with id test is inside a Grid whose content aggregation you have binded. This means that the whole VBox inside the grid (including the test VBox) is treated as a template for the content aggregation of the grid (i.e. with our JSON, you will end up having two copies of the VBox).
Using this.byId("test") will clearly not work, as it will return a control which is part of the Grid's content aggregation template. So be able to filter the inner VBoxes (because there will be several of them depending on the contents of the model), you have to iterate through the contents of the grid and apply the filtering to each of the target VBoxes. Something along the lines of:
this.byId("grid").getContent().forEach(function(oVbox) {
// need to get the HBox and the second VBox from it.
oVbox.getItems()[0].getItems()[1].getBinding("items").filter(...);
});
Also, both the Grid and the VBox have the same IDs, so your code will fail because of that as well. Generally, you don't need to define an ID for an aggregation template or a child.

Watson Conversation+TTS

I am trying to develop a web application using Watson Conversation service and Watson TTS service. The conversation output is sent to the TTS service for conversion. I am doing this in NodeRED and also i have put a function node between conversation node and TTS node which assigns the payload. After deployment I am only getting the conversational dialog chatbot but not the speech as I am suppose to. Please help me figure out what am I missing?
*PS: I am using HTTP post and HTTP get for this.
I built a flow that works and you will need to install a node that can play audio. The text to speech node does not actually play any sound. It creates an audio file.
Go to the hamburger in the upper right of the node red editor. Look for Palette Manager. look for node-red-contrib-play-audio and install it. I assume you have node-red-bluemix-nodes already.
you will need a node to retrieve the input, I used an inject node for the test.
connect it to your conversation node. Double click it and put the Workspace ID. (it is on the workspace under the three dots in the upper right of each one. Copy that long string into your node. I used the default car tutorial.
connect that to a function node. I then have to move the response from the conversation from msg.payload.output.text[0] to msg.payload like so:
msg.payload = msg.payload.output.text[0];
return msg;
connect that to a text to speech node. Fill in any credentials, pick a voice and click the output to msg.payload. If you forget to do this then the audio node will actually read the text instead of using the text to speech node's voice. The audio node's voice is not great.
connect the play audio node.
That is it. You should have a working voice.
A good way to see what is going on is to use a debug node. This lets you see where content is flowing and drop in functions to redirect the output appropriately for each node.
Copy the code below and go into the hamburger and do an import from clipboard to a new flow. You will need to fill in appropriate passwords and workspace ids but this shows how it is working.
[{
"id": "b7b6d9fc.1997f8",
"type": "tab",
"label": "Flow 2"
}, {
"id": "d0ed4492.045c18",
"type": "inject",
"z": "b7b6d9fc.1997f8",
"name": "",
"topic": "",
"payload": "play the radio",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"x": 159.5,
"y": 122,
"wires": [
["dc33249.3227bd8"]
]
}, {
"id": "dc33249.3227bd8",
"type": "watson-conversation-v1",
"z": "b7b6d9fc.1997f8",
"name": "",
"workspaceid": "",
"multiuser": false,
"context": true,
"default-endpoint": true,
"service-endpoint": "https://gateway.watsonplatform.net/conversation/api",
"x": 383.5,
"y": 121,
"wires": [
["d3c07b87.22f9c8"]
]
}, {
"id": "711b8067.a1c7",
"type": "debug",
"z": "b7b6d9fc.1997f8",
"name": "",
"active": true,
"console": "false",
"complete": "true",
"x": 751.5,
"y": 200,
"wires": []
}, {
"id": "9826b891.eb02b8",
"type": "watson-text-to-speech",
"z": "b7b6d9fc.1997f8",
"name": "",
"lang": "en-US",
"langhidden": "en-US",
"langcustom": "NoCustomisationSetting",
"langcustomhidden": "",
"voice": "en-US_MichaelVoice",
"voicehidden": "",
"format": "audio/wav",
"password": "",
"payload-response": true,
"default-endpoint": true,
"service-endpoint": "https://stream.watsonplatform.net/text-to-speech/api",
"x": 757.5,
"y": 64,
"wires": [
["ccf6f5a7.700508"]
]
}, {
"id": "d3c07b87.22f9c8",
"type": "function",
"z": "b7b6d9fc.1997f8",
"name": "",
"func": "msg.payload = msg.payload.output.text[0];\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 561.5,
"y": 120,
"wires": [
["9826b891.eb02b8", "711b8067.a1c7"]
]
}, {
"id": "ccf6f5a7.700508",
"type": "play audio",
"z": "b7b6d9fc.1997f8",
"name": "",
"voice": "0",
"x": 963.5,
"y": 64,
"wires": []
}]
Here is a link to a sample flow that uses Text to Speech on an HTML page. Take that as your starter, and add in Conversation.
https://github.com/watson-developer-cloud/node-red-labs/tree/master/basic_examples/text_to_speech
you need to provide more information about your problem.
anyway, one thing I've noticed is that text to speech generates a 44khz audio file. If you're running it locally in a RPI using some USB dongle, for example, it may not be able to play because it support by default 22Khz audio. So being able to play it locally also depends on the hardware and how the sound is configured in it.