Instead of a Label for a Node or an Edge, Id like to add an ICON - cytoscape.js

When looking at CytoscapeJs, i was noticing that a lot of the labels was accomplished by strings. Some sort of naming mechanism, but if i wanted to instead, say show a warning Icon for the Label of an EDGE or prepend a ICON to the existing Label for a Name, it seems there is nothing really to account for that.
I was looking at using things like unicode characters to define what is to be presented, but I have noticed 2 things. Depending on your level of zoom, the character would be a black rectangle, and also the characters are in some cases limited to the OS and Browser language packs.
I wanted to just be able to define an icon image, or use ionicons or something else to add this.
Note: I was also looking at the npm package: ctyoscape-node-label-html, which manages to encapsulate a Node with html, but it too has issues. 1. The package is called cytoscape-NODE-label-html and makes no mention in the documentation as to EDGE labels. 2. The last release was over 2 years ago, so i was thinking that maybe it meant that cytoscapejs has updated to the point where it has implemented the ability to add icons.
In the Commom Use cases of IonIcons, it usually just adds items based on class references, so i was thinking i might be able to add the classes and it would work without even touching the label, but i havent had much success.
Is there something i am missing with regard to Cytoscape? I have not seen any demos on their website, so being able to supply demos with how this would work would be fantastic.
I dont personally have any code at the moment, but one can use pretty much any of the sample cytoscapejs samples ( https://js.cytoscape.org/ ) as a jumping off platform for this Iconography.

Here is a demo code that uses icons fromIonIcons. Unfortunately, I have to use embedded SVG code for use in this demonstration, so that, I can manipulate it as needed.
// airplane.svg source:
// https://raw.githubusercontent.com/ionic-team/ionicons/main/docs/ionicons/svg/ios-airplane.svg
function airplane_mkr(fill_color,rot_angle) {
let airplane = '<svg xmlns="http://www.w3.org/2000/svg" width="80" height="50" viewBox="0 0 512 512"><g transform="rotate(rot_angle,256,256)"><path fill="fill_color" d="M407.7 224c-3.4 0-14.8.1-18 .3l-64.9 1.7c-.7 0-1.4-.3-1.7-.9L225.8 79.4c-2.9-4.6-8.1-7.4-13.5-7.4h-23.7c-5.6 0-7.5 5.6-5.5 10.8l50.1 142.8c.5 1.3-.4 2.7-1.8 2.7L109 230.1c-2.6.1-5-1.1-6.6-3.1l-37-45c-3-3.9-7.7-6.1-12.6-6.1H36c-2.8 0-4.7 2.7-3.8 5.3l19.9 68.7c1.5 3.8 1.5 8.1 0 11.9l-19.9 68.7c-.9 2.6 1 5.3 3.8 5.3h16.7c4.9 0 9.6-2.3 12.6-6.1L103 284c1.6-2 4.1-3.2 6.6-3.1l121.7 2.7c1.4.1 2.3 1.4 1.8 2.7L183 429.2c-2 5.2-.1 10.8 5.5 10.8h23.7c5.5 0 10.6-2.8 13.5-7.4L323.1 287c.4-.6 1-.9 1.7-.9l64.9 1.7c3.3.2 14.6.3 18 .3 44.3 0 72.3-14.3 72.3-32S452.1 224 407.7 224z"/></g></svg>';
airplane = airplane.replace("fill_color", fill_color);
airplane = airplane.replace("rot_angle", rot_angle);
const svg_Url = encodeURI("data:image/svg+xml;utf-8," + airplane);
return {"background-color":"#bbbbbb", "background-image":svg_Url, label:"data(name)", width:60, height:60, opacity:1.0};
}
//Colored/rotated airplanes icons
const pink_plane = airplane_mkr("pink","135");
const green_plane = airplane_mkr("green","90");
const gold_plane = airplane_mkr("gold","45");
const blue_plane = airplane_mkr("blue","60");
const red_plane = airplane_mkr("red","180");
var cy = cytoscape({
container: document.getElementById("cy"),
elements: {
nodes: [
{
data: { id: "j", name: "France" },
position: { x: 100, y: 100 },
classes: "FRA"
},
{
data: { id: "e", name: "SVG Icon" },
position: { x: 100, y: 500 },
classes: "SVG"
},
{
data: { id: "k", name: "Italy" },
position: { x: 600, y: 500 },
classes: "italy"
},
{
data: { id: "g", name: "The Netherlands" },
position: { x: 550, y: 80 },
classes: "netherlands"
}
],
edges: [
{ data: { source: "j", target: "e", label: "JE" } },
{ data: { source: "j", target: "g", label: "JG" } },
{ data: { source: "e", target: "j" } },
{ data: { source: "k", target: "j" } },
{ data: { source: "k", target: "e", label: "KE" } },
{ data: { source: "k", target: "g" } },
{ data: { source: "g", target: "j" } }
]
},
style: [
{
selector: "node.FRA",
style: pink_plane
},
{
selector: "node.SVG",
style: green_plane
},
{
selector: "node.italy",
style: gold_plane
},
{
selector: "node.netherlands",
style: blue_plane
},
{
selector: "node.FRA",
style: red_plane
},
{
selector: "edge",
style: {
label: "data(label)",
width: 3,
"line-color": "#c0c",
"target-arrow-color": "#00c",
"curve-style": "bezier",
"target-arrow-shape": "triangle",
"target-arrow-fill": "#c00",
"arrow-scale": 20
}
},
{
selector: ".highlight",
css: {
"background-color": "yellow"
}
}
],
layout: {
name: "preset"
}
});
#cy {
width: 800px;
height: 400px;
position: absolute;
top: 5px;
left: 5px;
}
ion-icon {
font-size: 64px;
color: blue;
--ionicon-stroke-width: 5px;
}
<script type="module" src="https://unpkg.com/ionicons#5.5.2/dist/ionicons/ionicons.esm.js"></script>
<script nomodule src="https://unpkg.com/ionicons#5.5.2/dist/ionicons/ionicons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/2.7.10/cytoscape.min.js"></script>
<div>
<span>Some ionicon icons</span><br/>
<ion-icon name="airplane" size="small"></ion-icon> <!--filled-->
<ion-icon name="airplane-sharp" size="large"></ion-icon> <!--sharp-->
<ion-icon name="airplane-outline"></ion-icon> <!--outline-->
</div><br/>
<div id="cy"></div>

Related

Is it possible to convert JSFiddle to VSCode format?

I'm trying to convert my jsfiddle code to VSCode, but I wasn't able to, as copy and pasting + code format editing were not working.
(jsfiddle link in question: https://jsfiddle.net/b2pLmqrj/ )
I've attempted to copy and paste it in, fix the format with tags (script, style, etc), and completely redo it from scratch, but to no avail. Does anyone know what I should fix in it to change it to VSCode format?
HTML:
<div id="map"></div>
CSS:
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
Javascript:
mapboxgl.accessToken = 'pk.eyJ1IjoiMWRyaXZlYnV5IiwiYSI6ImNsNjN1NjhjejBhZjYzaW44YXN0MzByb3YifQ.mykT1INa7Fbkk4VqIpdM_Q';
const map = new mapboxgl.Map({
container: 'map', // container ID
// Choose from Mapbox's core styles, or make your own style with Mapbox Studio
style: 'mapbox://styles/mapbox/light-v11', // style URL
center: [-68.137343, 45.137451], // starting position
zoom: 5 // starting zoom
});
map.on('load', () => {
// Add a data source containing GeoJSON data.
map.addSource('maine', {
'type': 'geojson',
'data': {
'type': 'Feature',
'geometry': {
'type': 'Polygon',
// These coordinates outline the United States.
'coordinates': [
[
[-125.15625000000001, 48.04870994288686],
[-124.71679687499999, 43.32517767999296],
[-125.15625000000001, 39.639537564366684],
[-121.11328124999999, 34.59704151614417],
[-121.11328124999999, 34.59704151614417],
[-117.158203125, 32.47269502206151],
[-105.732421875, 31.27855085894653],
[-97.20703125, 25.64152637306577],
[-84.287109375, 29.84064389983441],
[-80.947265625, 24.84656534821976],
[-74.970703125, 35.38904996691167],
[-66.62109375, 45.02695045318546],
[-68.73046875, 47.39834920035926],
[-71.455078125, 44.84029065139799],
[-82.880859375, 41.96765920367816],
[-88.154296875, 48.22467264956519],
[-109.072265625, 49.03786794532644],
[-123.134765625, 49.15296965617042],
[-125.15625000000001, 48.04870994288686],
]
]
}
}
});
// Add a new layer to visualize the polygon.
map.addLayer({
'id': ' ',
'type': 'fill',
'source': 'maine', // reference the data source
'layout': {},
'paint': {
'fill-color': '#0080ff', // blue color fill
'fill-opacity': 0.2
}
});
// Add a black outline around the polygon.
map.addLayer({
'id': 'outline',
'type': 'line',
'source': 'maine',
'layout': {},
'paint': {
'line-color': '#000',
'line-width': 0
}
});
});

How can I create a computed array in Vue and then render it using v-if all while using v-model on the computed array?

I've been trying to create a computed array which I then render using v-if. But it also needs to work with v-model. The reason it needs v-model is because it's part of a draggable list using vuedraggable.
Currently I get the following error Computed property "list" was assigned to but it has no setter.
The following code is my drag.vue component:
<template>
<div>
<draggable
v-model="list"
v-bind="dragOptions"
class="bigger-area"
#start="isDragging=true"
#end="isDragging=false"
>
<transition-group name="flip-list" type="transition">
<li
v-for="text in list"
:key="text"
id="list1"
class="drag-item flex flex-justify-betweeen"
>{{ text }}</li>
</transition-group>
</draggable>
</div>
</template>
<script>
import draggable from "vuedraggable";
export default {
name: "Drag",
data() {
return {
test: [],
lists: [
{
title: "0-6 months",
correctlyOrderedList: [
"Lifting Head",
"Rolling",
"Sitting (with support)"
]
},
{
title: "6-12 months",
correctlyOrderedList: [
"Crawling on stomach",
"Sitting (without support)",
"Stands with support and walks holding on",
"Rolls a ball"
]
},
{
title: "12-18 months",
correctlyOrderedList: ["Crawling", "Walks alone"]
},
{
title: "18 months – 2 years",
correctlyOrderedList: [
"Walks smoothly and turns corners",
"Walks upstairs with support",
"Begins running"
]
},
{
title: "2-3 years",
correctlyOrderedList: [
"Walks upstairs without support",
"Runs safely",
"Catches using body and arms"
]
},
{
title: "3-4 years",
correctlyOrderedList: ["Kicks a ball forwards", "Can hop on one foot"]
},
{
title: "4-5 years",
correctlyOrderedList: [
"Catches using only their hands",
"Can skip following a demonstration"
]
}
]
};
},
components: {
draggable
},
methods: {
fullArrayMethod() {
//Puts all statements into single array
let i;
let v;
let fullArrayInOrder = [];
for (i = 0; i < this.lists.length; i++) {
for (v = 0; v < this.lists[i].correctlyOrderedList.length; v++) {
fullArrayInOrder.push(this.lists[i].correctlyOrderedList[v]);
}
}
return fullArrayInOrder;
},
disorderedArrayMethod() {
//Randomizes array
let fullArrayInOrder = this.fullArrayMethod();
var copy = [],
n = fullArrayInOrder.length,
i;
// While there remain elements to shuffle…
while (n) {
// Pick a remaining element…
i = Math.floor(Math.random() * fullArrayInOrder.length);
// If not already shuffled, move it to the new array.
if (i in fullArrayInOrder) {
copy.push(fullArrayInOrder[i]);
delete fullArrayInOrder[i];
n--;
}
}
return copy;
},
chunk(array, size) {
const chunked_arr = [];
let index = 0;
while (index < array.length) {
chunked_arr.push(array.slice(index, size + index));
index += size;
}
return chunked_arr;
},
splitArrayFinalProduct() {
let disorderedArray = this.disorderedArrayMethod();
let finalArray = this.chunk(disorderedArray, 3);
return finalArray;
}
},
computed: {
dragOptions() {
return {
animation: 0,
group: "shared",
disabled: false,
ghostClass: "ghost"
};
},
list() {
return this.disorderedArrayMethod();
}
}
};
</script>
Context: I'm trying to create an application which consolidates multiple arrays into one. Randomises the array. The user can then put it back in order and then see if they got it right.
For anyone who may find it useful this is what worked for me. I can't explain the in's and outs of why it works so hopefully somebody smarter than me can elaborate.
To get the computed array variable to work with v-model and v-for I used map() as shown below:
let completeListOfStatements = this.lists.map(
d => d.correctlyOrderedList
);
My understanding of map() is it returns an array.
Then in the v-model I set it to the array that is within the object. This is the same one that I used map() on. This can be seen below.
<draggable
v-model="lists.correctlyOrderedList"
v-bind="dragOptions"
class="list-group"
#start="isDragging=true"
#end="isDragging=false"
>
For comparisons to the code in my question here's all the code from the component:
<template>
<div class="draggable-list-container">
<div
class="draggable-list-inner-container"
v-for="(statement, index) in splitCompleteListOfStatements"
:key="index"
>
<h1>{{ lists[index].title }}</h1>
<draggable
v-model="lists.correctlyOrderedList"
v-bind="dragOptions"
class="list-group"
#start="isDragging=true"
#end="isDragging=false"
>
<transition-group name="flip-list" type="transition">
<li
v-for="(statement, index) in statement"
:key="index + 'index'"
class="drag-item flex flex-justify-betweeen"
>{{ statement }}</li>
</transition-group>
</draggable>
</div>
<div class="submit-button-container">
<button class="btn" #click="revealAnswers">Reveal answers</button>
</div>
</div>
</template>
<script>
import draggable from "vuedraggable";
export default {
name: "Drag",
data() {
return {
lists: [
{
title: "0-6 months",
correctlyOrderedList: [
"Lifting Head",
"Rolling",
"Sitting (with support)"
]
},
{
title: "6-12 months",
correctlyOrderedList: [
"Crawling on stomach",
"Sitting (without support)",
"Stands with support and walks holding on",
"Rolls a ball"
]
},
{
title: "12-18 months",
correctlyOrderedList: ["Crawling", "Walks alone"]
},
{
title: "18 months – 2 years",
correctlyOrderedList: [
"Walks smoothly and turns corners",
"Walks upstairs with support",
"Begins running"
]
},
{
title: "2-3 years",
correctlyOrderedList: [
"Walks upstairs without support",
"Runs safely",
"Catches using body and arms"
]
},
{
title: "3-4 years",
correctlyOrderedList: ["Kicks a ball forwards", "Can hop on one foot"]
},
{
title: "4-5 years",
correctlyOrderedList: [
"Catches using only their hands",
"Can skip following a demonstration"
]
}
]
};
},
components: {
draggable
},
methods: {
disorderedArrayMethod(value) {
//Randomizes array
let fullArrayInOrder = value;
var copy = [],
n = fullArrayInOrder.length,
i;
// While there remain elements to shuffle…
while (n) {
// Pick a remaining element…
i = Math.floor(Math.random() * fullArrayInOrder.length);
// If not already shuffled, move it to the new array.
if (i in fullArrayInOrder) {
copy.push(fullArrayInOrder[i]);
delete fullArrayInOrder[i];
n--;
}
}
return copy;
},
revealAnswers() {this.splitCompleteListOfStatements[0].push("Hello")}
},
computed: {
dragOptions() {
return {
animation: 0,
group: "shared",
disabled: false,
ghostClass: "ghost"
};
},
splitCompleteListOfStatements() {
let completeListOfStatements = this.lists.map(
//Maps out full array (Basically loops through gathers the arrays and creates an array from them)
d => d.correctlyOrderedList
);
completeListOfStatements = completeListOfStatements.reduce(function(
//The map returns an array as the following [[a,b], [], []] etc. So this turns it into [a,b,c,d]
a,
b
) {
return a.concat(b);
}, []);
completeListOfStatements = this.disorderedArrayMethod(
completeListOfStatements
); //This sends it to a method that jumbles the array
var temp = [];
var preVal = 0;
var nextVal = 3;
for (var i = 0; i < 7; i++) {
temp.push(completeListOfStatements.slice(preVal, nextVal));
preVal = nextVal;
nextVal = nextVal + 3;
}
return temp;
}
}
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.title {
margin-bottom: 0.5em;
}
.submit-button-container {
margin-top: 5px;
}
.btn {
width: 10em;
height: 5em;
}
.draggable-list-container {
display: inline-block;
justify-content: center;
min-height: 200px;
}
.list-group {
min-height: 80px;
}
.drag-item {
justify-content: center;
padding: 15px 10px;
background-color: whitesmoke;
border: 1px solid black;
width: 20em;
margin: 2px;
cursor: move;
}
.list-group-item {
position: relative;
display: block;
padding: 0.75rem 1.25rem;
margin-bottom: -1px;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, 0.125);
}
.flip-list-move {
transition: transform 0.5s;
}
.no-move {
transition: transform 0s;
}
.ghost {
opacity: 0.5;
background: #c8ebfb;
}
.list-group-item {
cursor: move;
}
</style>

Cytoscape.js: Overlapping edge labels in multigraph

There are several posts about edge or edge label overlaps in Cytoscape.js but the answers given there, like smaller labels and more spaced out nodes, don't help for a multigraph, i.e. a graph where two nodes can have multiple edges between them.
Is there a way to spread out edge labels even if they all belong to edges between the same two nodes? The edge pairs occur both in the same direction and in the reverse one.
As my graph is verly large, I would prefer a solution with haystack edges as the performance is already low.
Well you can rotate the text with "text-rotation": "autorotate" in the labels css. You can also define the "text-margin-x/y" for each node itself, but how do you plan on defining the position for each and every label? Lets assume, you did that perfectly: you would still need to do a reposition event after moving just one node, because the offsets will be off by then:
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
boxSelectionEnabled: false,
autounselectify: true,
style: [{
selector: "node",
css: {
content: "data(id)",
"text-valign": "center",
"text-halign": "center",
height: "60px",
width: "60px",
"border-color": "black",
"border-opacity": "1",
"border-width": "10px"
}
},
{
selector: "$node > node",
css: {
"padding-top": "10px",
"padding-left": "10px",
"padding-bottom": "10px",
"padding-right": "10px",
"text-valign": "top",
"text-halign": "center",
"background-color": "#bbb"
}
},
{
selector: "edge",
css: {
"target-arrow-shape": "triangle"
}
},
{
selector: "edge[label]",
css: {
"label": "data(label)",
"text-rotation": "autorotate",
"text-margin-x": "data(xalign)",
"text-margin-y": "data(yalign)"
}
},
{
selector: ":selected",
css: {
"background-color": "black",
"line-color": "black",
"target-arrow-color": "black",
"source-arrow-color": "black"
}
}
],
layout: {
name: "circle"
}
}));
var info = [{
name: "Peter",
next_op_name: "Claire"
},
{
name: "Claire",
next_op_name: "Mike"
},
{
name: "Mike",
next_op_name: "Rosa"
},
{
name: "Rosa",
next_op_name: "Peter"
}
];
cy.ready(function() {
var array = [];
// iterate over info once
for (var i = 0; i < info.length; i++) {
array.push({
group: "nodes",
data: {
id: info[i].name, // id is name!!!
label: info[i].name
}
});
array.push({
group: "edges",
data: {
id: "e" + i,
source: info[i].name,
target: info[i].next_op_name,
label: "e" + i,
xalign: (i == 0 || i == 1 ? '15px' : '-15px'),
yalign: (i == 0 || i == 3 ? '15px' : '-15px')
}
});
}
cy.add(array);
cy.layout({
name: "circle"
}).run();
});
cy.on("mouseover", "node", function(event) {
var node = event.target;
node.qtip({
content: "hello",
show: {
event: event.type,
ready: true
},
hide: {
event: "mouseout unfocus"
}
},
event
);
});
cy.on("tapdrag", "node", function(event) {
// update all relevant labels
var labels = event.target.connectedEdges();
for (var i = 0; i < labels.length; i++) {
// render with the right positions?
}
});
body {
font: 14px helvetica neue, helvetica, arial, sans-serif;
}
#cy {
height: 100%;
width: 75%;
position: absolute;
left: 0;
top: 0;
float: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<meta charset=utf-8 />
<meta name="viewport" content="user-scalable=no, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, minimal-ui">
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.2.17/cytoscape.min.js"></script>
<!-- qtip imports -->
<script src="https://unpkg.com/jquery#3.3.1/dist/jquery.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.min.js"></script>
<link href="http://cdnjs.cloudflare.com/ajax/libs/qtip2/2.2.0/jquery.qtip.min.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-qtip/2.7.0/cytoscape-qtip.js"></script>
<!-- dagre imports -->
<script src="https://unpkg.com/dagre#0.7.4/dist/dagre.js"></script>
<script src="https://cdn.rawgit.com/cytoscape/cytoscape.js-dagre/1.5.0/cytoscape-dagre.js"></script>
</head>
<body>
<div id="cy"></div>
</body>
</html>
The problem breaks down to this: the task seems simple, but keeping track of the positions of all nodes and the edges aaaaand your rendered labels is a sisyphean task.

SignalR values with Kendo UI Asp.net wrappers

I have a Kendo UI datawiz component, RadialGauge, which I would like to feed with real time data. It's setup using the asp.net wrappers, like so (snipped from kendo demos):
<div id="gauge-container-center">
#(Html.Kendo().RadialGauge()
.Name("tensionGauge")
.Pointer(pointer => pointer.Value(28))
.Scale(scale => scale
.MinorUnit(5)
.StartAngle(-60)
.EndAngle(240)
.Max(180)
.Labels(labels => labels
.Position(GaugeRadialScaleLabelsPosition.Inside)
)
.Ranges(ranges =>
{
ranges.Add().From(80).To(120).Color("#ffc700");
ranges.Add().From(120).To(150).Color("#ff7a00");
ranges.Add().From(150).To(180).Color("#c20000");
})
)
)
</div>
All the underlying functionality is for "real time" data is setup and working fine. My only issue is how I would go about feeding the signalR value into the .Pointer(pointer => pointer.Value(signalRValueHere) part. Any suggestions on how to do this? It doesn't seem to be an abundance of examples combining these two frameworks yet, so search results are scarce.
Ok, so I solved this using a different approach. I opted to use the javascript-initializer instead, allowing me to utilize SignalR-values in the script.
function createGauge() {
$("#tensionGauge").kendoRadialGauge({
pointer: {
value: 0,
color: "black",
},
cap: {
color: "white",
size: 1
},
scale: {
minorUnit: 50,
majorUnit: 100,
startAngle: -50,
endAngle: 230,
min: #Convert.ToInt32(Model.MinTensionRange),
max: #Convert.ToInt32(Model.MaxTensionRange),
labels: {
position: "inside"
},
ranges: [ // TODO: Fetch limits from signalR or Model
{
from: 300,
to: 100,
color: "#ffc700"
},{
from: -300,
to: -100,
color: "#ffc700"
}, {
from: #Convert.ToInt32(Model.MinTensionRange),
to: -300,
color: "#c20000"
},{
from: #Convert.ToInt32(Model.MaxTensionRange),
to: 300,
color: "#c20000"
}
]
}
});
}
$(document).ready(function () {
createGauge();
});
And the js-part to update the value:
messageHub.client.notifyTension = function (tensionMessage) {
$('#tensionGauge').data("kendoRadialGauge").value(tensionMessage);
};

SenchaTouch onItemDisclosure 2 icons

I have a list and I want have two icons per line using onItemDisclosure. How can I do that?
I don't know how to implement onItemDisclousre() on two icons but probably this will help you.
In the following example i have put an image on every itemlist and functionality is provided on itemtap event. This will serve the purpose of doing multiple tasks with single itemlist.
//demo.js
Ext.define("Stackoverflow.view.demo", {
extend: "Ext.Container",
requires:"Ext.dataview.List",
alias: "widget.demo",
config: {
layout: {
type: 'fit'
},
items: [
{
xtype: "list",
store: "store",
itemId:"samplelist",
loadingText: "Loading Notes...",
emptyText: "<div class=\"notes-list-empty-text\">No notes found.</div>",
onItemDisclosure: true,
itemTpl:"<div class='x-button related-btn' btnType='related' style='border: none; background: url(\"a.png\") no-repeat;'></div>"+
"<div class=\"list-item-title\">{title}</div>"
grouped: true
}
],
listeners:
[
{
delegate: "#samplelist",
event: "disclose",
fn: "onDiscloseTap"
}
]
},
onDiscloseTap: function (list, record, target, index, evt, options) {
this.fireEvent('ondisclosuretap', this, record);
}
});
// Democontrol.js
Ext.define("Stackoverflow.controller.Democontrol", {
extend: "Ext.app.Controller",
config: {
refs: {
// We're going to lookup our views by xtype.
Demo: "demo",
Demo1: "demo list",
},
control: {
Demo: {
ondisclosuretap: "Disclosure",
},
Demo1: {
itemtap:"imagetap"
}
}
},
Disclosure: function (list, record,target,index,e,obj) {
Ext.Msg.alert('','Disclosure Tap');
},
imagetap: function (dataview,index,list,record, tar, obj) {
tappedItem = tar.getTarget('div.x-button');
btntype = tappedItem.getAttribute('btnType');
if(btntype == 'related')
{
Ext.Msg.alert('','Image/Icon Tap');
}
},
// Base Class functions.
launch: function () {
this.callParent(arguments);
},
init: function () {
this.callParent(arguments);
}
});
//app.css
.related-btn
{
width: 100px;
height: 100px;
position: absolute;
bottom: 0.85em;
right: 2.50em;
-webkit-box-shadow: none;
}
Hope this will help you.
bye.
You can do this by manually adding a disclosure icon inside of itemTpl on your list items. Add this inside of your view:
{
xtype: 'list',
onItemDisclosure: true,
cls: 'my-list-cls',
itemTpl: [
'<div class="x-list x-list-disclosure check-mark" style="right: 48px"></div>'
]
}
Notice that the div inside of itemTpl has the CSS class "x-list x-list-disclosure check-mark". I set style="right: 48px" because I want this icon to appear on the left side of the regular disclosure icon (the one with the right arrow) and this rule leaves enough room on the right to show the arrow icon.
Then, in your app.scss, add:
.my-list-cls {
.x-list.check-mark.x-list-disclosure:before {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
content: '3';
font-family: 'Pictos';
color: #fff;
text-align: center;
text-shadow: 0 0 0;
}
}
This controls the styling for your new disclosure icon.
By setting content: '3';, you are changing the icon from the default right arrow to a checkmark. (See all of the available icons here: Pictos fonts).
The result:
It is possible but not easy. In short you have to extend class Ext.dataview.List and/or Ext.dataview.element.List.