I'm new here, I'm working with Angular UI-Grid, and I have a small problem. The grid that I handle has a tree structure, that works perfect. But to make it easier to follow that structure for the user, I want to implement different colors per level.
I have created this Plunker with two examples, the first is how you should see the different colors per level, and the second is how it behaves today. Has anyone done something like this or do you have any idea how to fix it?
app.js:
var app = angular.module('app', ['ui.grid','ui.grid.treeView']);
app.controller('MainCtrl', ['$scope', '$http','uiGridTreeViewConstants', function ($scope, $http, uiGridTreeViewConstants) {
$scope.myData = [
{"ubi_id":321,"ubi_nom":"America","ubi_pad_id":null,"ubi_tip_id":1,"$$treeLevel":0},
{"ubi_id":322,"ubi_nom":"Sudamerica","ubi_pad_id":321,"ubi_tip_id":2,"$$treeLevel":1},
...
];
var rowtpl = '';
rowtpl += '<div ng-class="{\'nivelGrilla-{{row.entity.$$treeLevel}}\': row.entity.$$treeLevel != \'undefined\' }">';
rowtpl += '<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name"';
rowtpl += 'class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell>';
rowtpl += '</div></div>';
$scope.gridOptions = {
data:'myData',
rowTemplate:rowtpl,
};
}]);
css:
.nivelGrilla-0{
background-color: #254158;
color: white;
}
.nivelGrilla-1{
background-color: #3F6F96;
color: white;
}
html:
<div id="grid1" ui-grid="gridOptions" ui-grid-tree-view class="grid"></div>
I found a solution, the div that contains the entire row, makes a call to a function that returns the name of the class according to the row level.
Here's a plnkr with my solution
js:
var rowtpl = '';
rowtpl += '<div class=\"{{grid.appScope.rowLevel(row)}}\">';
rowtpl += '<div ng-repeat="(colRenderIndex, col) in colContainer.renderedColumns track by col.colDef.name"';
rowtpl += 'class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell>';
rowtpl += '</div>';
rowtpl += '</div>';
$scope.gridOptions2 = {
data:'myData',
rowTemplate:rowtpl,
};
css:
.ui-grid-row .ui-grid-cell {
background-color: inherit !important;
color: inherit !important;
}
.ui-grid-row .ui-grid-cell.ui-grid-cell {
background-color: #f0f0ee;
border-bottom: solid 1px #d4d4d4;
}
.rowLevel-0{
background-color: #254158;
color: white;
}
.rowLevel-1{
background-color: #3F6F96;
color: white;
}
.rowLevel-2{
background-color: #5289B6;
}
You can specify a 'cellClass' within your grid's 'columnDefs' and switch the rows according to the tree level. For example:
$scope.gridOptions = {
data:'myData',
columnDefs: [
{ field: 'Id', name: 'Ubi Id'},
{ field: 'Country', name: 'Ubi Nom'},
cellClass: function(grid, row, col, rowRenderIndex, colRenderIndex) {
switch(row.treeLevel)
{
case 0:
return 'red';
case 1:
return 'blue';
case 2:
return 'green';
default:
break;
}
}
]
};
Related
I need to be able to resize, rotate, and move an image. I have managed to find the code below that works but I need to either have a rotation point on the image where I can use it to rotate it with mouse or have the slider to move with the image. The problem starts when the image and the slider are too far apart. I would prefer to have the slider as part of the image if possible, somehow connected. Many thanks in advance for your help. The image is a protractor where it needs to be moved and rotated to measure angles.
Below is my codes
HTML
<!-- Mockup img downloaded from www.magicmockups.com -->
<!-- Change the mockup image to any image of your choice in the img tag bellow. -->
<!-- XXX: WARNING: When the pen is saved, the movable div is RESET to the original
position/size/rotation. -->
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
</div>
<div style="margin-top: 20px">ROTATION SLIDER:</div>
<div id="slider" style="display:inline-block; width: 50%; margin: 10px 0 10px1 0px;">
</div>
<div style="display: inline-block; position: relative;">
<!-- CHANGE IMG TO YOUR IMG -->
<div id="movable" >https://link to image</div>
Javascript
var currentUnit = "pixels"
$( function() {
$("input[type=radio]").checkboxradio();
$("#slider").slider({
min: -360,
max: 360,
slide: function(event, ui) {
// Set the slider's correct value for "value".
$(this).slider('value', ui.value);
$("#movable").css('transform', 'rotate(' + ui.value + 'deg)')
updateText()
}
});
$("#movable").draggable({
drag: function(event, ui) {
updateText()
}
})
$("#movable").resizable({
resize: function(event, ui) {
updateText()
}
})
// Init the text.
updateText();
});
function getPixelDimensions() {
precision = 100
// Save current transform (rotation).
originalTransform = $("#movable").css('transform')
// Remove rotation to make sure position() is the CSS position, not the bounding rect
position.
$("#movable").css('transform', 'rotate(0deg)')
position = $("#movable").position()
// Restore rotation.
$("#movable").css('transform', originalTransform)
dim = {
top: Math.round(position.top * precision) / precision,
left: Math.round(position.left * precision) / precision,
width: Math.round($("#movable")[0].clientWidth * precision) / precision,
height: Math.round($("#movable")[0].clientHeight * precision) / precision
}
return dim;
}
function getPercentageDimensions() {
}
function updateText() {
if(currentUnit == "pixels") {
dim = getPixelDimensions();
sufix = "px"
} else {
dim = getPercentageDimensions();
sufix = "%"
}
$(".d").remove()
for(prop in dim) {
$("#dimensions").append( "<div class='d'>" + prop + ": " + dim[prop] + sufix + "</div>");
}
$("#dimensions").append( "<div class='d'>rotate: " + $("#slider").slider("value") +
"deg</div>");
//console.log($("#outer").position().top)
}
$('input').change(function() {
if(this.id == "radio-1") {
currentUnit = "pixels";
updateText();
} else if(this.id.search("radio") != -1){
currentUnit = "percentage";
updateText();
}
})
function previewFile() {
var preview = document.querySelector('img'); //selects the query named img
var file = document.querySelector('input[type=file]').files[0]; //sames as here
var reader = new FileReader();
reader.onloadend = function () {
preview.src = reader.result;
}
if (file) {
reader.readAsDataURL(file); //reads the data as a URL
} else {
preview.src = "";
}
}
CSS
#movable {
position: absolute;
text-align: center;
/*Manually change values here.*/
width: 400px;
height: 400px;
top: 0px;
left: 0px;
transform: rotate(0deg);
}
I've added the placeholder widget to my CKEditor 5 build. However I don't like that I can't change the text after it is inserted. I tried removing isObject from the schema but that didn't do anything. I'd appreciate it if someone could show me how this can be achieved.
In version 4 the edit of the text is done via popup called by double clicking on the placeholder: https://ckeditor.com/cke4/addon/placeholder
In version 5 the placeholder was not fully implemented intentionally
"We didn't decide, though to implement a ready-to-use placeholder feature as it's usually needed to work differently in various systems"
https://github.com/ckeditor/ckeditor5/issues/871
So the only thing you can do is to implement the function you are missing yourself. I suggest looking at how version 4 does and understanding if it is applicable to version 5.
I have implemented it just with additional HTML block and control it with state (in my case I'm using React).
const CKInlineEditorField = ({
defaultValue = '',
onChange,
placeholder = '',
}) => {
const [showPlaceholder, setShowPlaceholder] = useState(false);
const { t } = useTranslation();
useEffect(() => {
if (!defaultValue) {
setShowPlaceholder(true);
}
}, [defaultValue]);
return (
<div>
<Paper variant="outlined" className="InlineEditor">
<div className="InlineEditor__placeholder">
{showPlaceholder && `${t(placeholder)}...`}
</div>
<div className="InlineEditor__editor">
<CKEditor
editor={InlineEditor}
data={defaultValue}
onChange={(event, editor) => {
const data = editor.getData();
setShowPlaceholder(!data);
}}
onBlur={(event, editor) => {
const data = editor.getData();
onChange(data);
}}
/>
</div>
</Paper>
</div>
);
};
And SCSS file:
.InlineEditor {
background-color: #eee;
position: relative;
&__placeholder {
position: absolute;
top: 15px;
left: 10px;
z-index: 0;
}
&__editor {
position: relative;
z-index: 2;
}
}
I have an XYChart with data object like
chart.data = [{
"Area": "Korangi",
"AreaNumber": 120,
"SubArea": [{
"SubAreaName": "Korangi-1",
"SubAreaNumber": 60
}, {
"SubAreaName": "Korangi-2",
"SubAreaNumber": 60
}
]
}];
and a series tooltipHTML adapter as
series.tooltipHTML = `<center><strong> {Area}:</strong>
<strong> {AreaNumber}%</strong></center>
<hr />`;
series.adapter.add("tooltipHTML",
function (html, target) {
if (
target.tooltipDataItem.dataContext &&
target.tooltipDataItem.dataContext.SubArea &&
target.tooltipDataItem.dataContext.SubArea.length
) {
var nameTalClientsNumberCells = "";
Cells = "";
target.tooltipDataItem.dataContext.SubArea.forEach(part => {
if (part.SubAreaName != null) {
nameTalClientsNumberCells +=
`<tr><td><strong>${part.SubAreaName}</strong>:  ${part
.SubAreaNumber}%</td></tr>`;
}
//TalClientsNumberCells += `<td>${part.SubAreaNumber}</td>`;
});
html += `<table>
${nameTalClientsNumberCells}
</table>`;
}
return html;
});
For I have tried bootstrap classes but non of them works in tooltipHTML.
what I want is like this
but I tried so far is like this
Please help or refer if there is another way of adding really rich HTML in tooltip
A link to the codepen
What you're doing is fine. I just didn't see you used any bootstrap4 css class. You can achieve what you want with either bootstrap4 built-in classes, or your own custom styles.
//I don't need to set tooltipHTML since I have the adapter hook up to return
// custom HTML anyway
/*
series.tooltipHTML = `<center><strong> {Area}:</strong>
<strong> {AreaNumber}%</strong></center>
<hr />`;
*/
series.adapter.add("tooltipHTML", function (html, target) {
let data = target.tooltipDataItem.dataContext;
if (data) {
let html = `
<div class="custom-tooltip-container">
<div class="col-left">
<h5>${data.Area}</h5>
<ul class="list-unstyled">
${data.SubArea.map(part =>
`
<li class="part">
<span class="name">${part.SubAreaName}</span>
<span class="area">${part.SubAreaNumber}%</span>
</li>
`
).join('')}
</ul>
</div>
<div class='col-right'>
<span class="badge badge-pill badge-success">${data.AreaNumber}%</span>
</div>
</div>
`;
return html;
}
return '';
});
And here is the custom styles:
#chart {
height: 31rem;
}
.custom-tooltip-container {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
min-width: 13rem;
}
.custom-tooltip-container .col-left {
width: 70%;
}
.custom-tooltip-container .col-right {
width: 30%;
text-align: center;
}
.custom-tooltip-container .col-right .badge {
font-size: 1.1rem;
}
.custom-tooltip-container .part {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
}
Again, you can do whatever you want. Here as demo I just quickly put things together.
demo: https://jsfiddle.net/davidliang2008/6g4u2qw8/61/
In the example below, the split button should remove all semicolons and create a new editor with the following text until the next semicolon.
However, there is an odd bug where all editors except the first one have the cursor flashing at the end of the line, but only the last field has actually got the cursor (e.g. typing after pressing split will put text in the last field). How do I prevent this?
$(function() {
function aceinit() {
var e = ace.edit(this),
t = $(this);
e.setTheme("ace/theme/sqlserver");
e.setOptions({
maxLines: Infinity,
highlightActiveLine: false,
tabSize: 8,
useSoftTabs: false,
fixedWidthGutter: true
});
e.getSession().setMode("ace/mode/sql");
e.getSession().on('change', function() {
$('.output').css('opacity', '0.3');
$('.markdown-toggle').hide();
});
e.commands.bindKey("Tab", null);
e.commands.bindKey("Shift-Tab", null);
e.setAutoScrollEditorIntoView(true);
return e;
}
$('.ace').each(function() {
aceinit.call(this);
});
$('body').on('click', '.plus', function() {
$('main').children().slice(0, 3).clone().insertBefore($(this));
$('.ace').each(function() {
aceinit.call(this);
});
var b = $(this).prev().prev('.batch');
var e = aceinit.call(b.find('.ace').get(0));
e.setValue("");
e.resize();
e.focus();
b.find('.results').html('');
});
$('body').on('click', '.split', function() {
var b = $(this).prev('.batch');
e = ace.edit(b.find('.ace').get(0));
s = ';';
b.find('.results').html('');
setTimeout(function() {
var split = e.getValue().split((new RegExp(s, 'im')));
$.each(split, function(i, v) {
if (v.trim()) {
if (i > 0) {
if (!b.find('.ace').filter(function() {
return ace.edit(this).getValue() === '';
}).length) {
b.next().next('.plus').click();
}
b = b.nextAll().eq(2);
e = ace.edit(b.find('.ace').get(0));
}
e.setValue(split[i].replace(/\s+$/, '').replace(/^\s+/, ''), 1);
}
});
}, 0);
});
});
.batch {
flex-direction: column;
min-width: 0;
overflow-x: hidden;
margin-left: 0.5em;
}
.query.ace {
border: 1px solid #aaa;
height: 1em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://dbfiddle.uk/ace/ace.js"></script>
<main>
add batch
<div class="batch" style="display: flex;">
<div class="ace query">text1
;
text2
;
text3
;
text4
;
text5
;</div>
</div>
split
add batch
</main>
this happens because you are calling
e.focus();
after creating each editor, call it only for the one which you want to be focused.
I'm using Kendo UI and trying to display multiple charts on a single web page. Everything works until I try to add a second bar chart. One of the charts does not display and just shows a generic chart image (it looks like it is not finding the data but if I reorder they reverse what is happening). I can display multiple line charts. Any ideas about what might be happening?
Below is my html for the two charts without the SVG info:
<div kendo-chart="" k-options="vm.barChartOptions" ng-show="this.dataItem.visible" class="move k-block ng-scope k-chart" id="costPerPound" style="float: left; margin: 5px 0px; position: relative;" data-uid="b543ff9a-ee57-4ce7-a39d-8f69a0505a2b" role="option" aria-selected="false" data-role="chart"></div>
<div kendo-chart="" k-options="vm.barChartOptions" ng-show="this.dataItem.visible" class="move k-block ng-scope k-chart" id="numShipments" style="float: left; margin: 5px 0px; position: relative;" data-uid="97094bf1-4366-4974-b92f-edf36d1980f4" role="option" aria-selected="false" data-role="chart"></div>
Here are is the k-options info. As you can see I am setting most of my information at render.
vm.barChartOptions = {
dataSource: vm.chartData_datasource,
series: [
{
}
],
valueAxis: {
line: {
visible: false
},
labels: {
rotation: "auto"
}
},
tooltip: {
visible: true,
template: "#= series.name #: #= value #"
},
render: function (e) {
var chart = e.sender;
var chartData = vm.findChartData(e);
if (chartData != null) {
chartData.categoryAxisField = vm.firstToLower(chartData.categoryAxisField);
chart.options.title.text = chartData.title;
chart.options.name = chartData.htmlID;
chart.options.categoryAxis.field = chartData.categoryAxisField;
chart.options.categoryAxis.labels.format = chartData.categoryAxisLabel;
chart.options.legend.position = chartData.legendPosition;
chart.options.seriesDefaults.type = chartData.chartType;
for (var i = 0; i < chart.options.series.length; i++) {
chart.options.series[i].type = chartData.chartType;
chart.options.series[i].field = vm.firstToLower(chartData.dataField);
}
}
}
}
I had same issue. It can be resolved by just providing different name
to each chart.