Text object styling not set correctly when loading canvas from serialized data - konvajs

I have created a custom label maker using the Konvajs library. I provided the user with a label library to choose from as a starting point or the option to create a label from scratch. If the user selects from the label library I load the label via Json and I provide the user with the ability to edit any text elements with external controls. The user has the ability to set the following properties:
fontFamily
fontSize
fontStyle
fontVariant
lineHeight
fill
align
When the user clicks on a text object on the canvas the external controls are set with the text objects properties allowing the user to modify any of the properties listed above.
The issue I'm having is when the label is loaded the text format is the default until the user clicks on the text to edit, then all the pre-set properties are applied. I need the pre-set properties to display when first loaded.
Here is my function for loading the Json:
function loadCanvasFromJson(json) {
//Remove the disable class from action buttons...
$('.dropdown-action-btn').addClass('disabled');
stage = Konva.Node.create(json, 'labelcontainer');
stage.find('Image').forEach((imageNode) => {
const src = imageNode.getAttr('src');
const image = new Image();
image.onload = () => {
imageNode.image(image);
imageNode.getLayer().batchDraw();
}
image.src = src;
});
stage.find('Text').forEach((textNode) => {
textNode.on("mouseover", function(e){
document.body.style.cursor = 'pointer';
});
textNode.on('mouseout', function() {
document.body.style.cursor = 'default';
});
textNode.on('click', function(evt) {
var text = evt.target;
$('#add-label-text').addClass('hidden');
$('#update-label-text').removeClass('hidden');
$('#delete-label-text').removeClass('hidden');
setTextClickValues(text);
});
});
}
Here is the function for setting the external editor controls when a text object is clicked:
function setTextClickValues(text) {
var textObj = text.getAttrs();
console.log(textObj);
for (attr in textObj) {
if (attr == 'align') {
$('#text-align').val(text.getAttr(attr));
if (text.getAttr(attr) == 'center')
$('.text-format-text-align-center').addClass('active');
if (text.getAttr(attr) == 'left')
$('.text-format-text-align-left').addClass('active');
if (text.getAttr(attr) == 'right')
$('.text-format-text-align-right').addClass('active');
}
if (attr == 'id') $('#text-group').val(text.getAttr(attr).replace('text',''));
if (attr == 'text') $('#label-text').val(text.getAttr(attr));
if (attr == 'lineHeight') {
$('#text-lineheight').val(text.getAttr(attr));
$('#lineHeight').val(text.getAttr(attr));
}
if (attr == 'fontSize') {
$('#text-size').val(text.getAttr(attr));
$('#fontSize').val(text.getAttr(attr));
}
if (attr == 'fill') {
$('#text-fill').val(text.getAttr(attr));
$('.colorPickSelector.fill').css('background-color', text.getAttr(attr));
$('.colorPickSelector.fill').css('color', text.getAttr(attr));
if (text.getAttr(attr) == '#ffffff') {
$('.colorPickSelector.fill').css('border','1px solid rgb(221, 221, 221)');
}
}
if (attr == 'fontFamily') {
$('.text-format-dropdown-current').val(text.getAttr(attr));
$('#text-font').val(text.getAttr(attr));
}
if (attr == 'fontVariant') {
$('#text-fontVariant').val(text.getAttr(attr));
if (text.getAttr(attr) == 'small-caps')
$('.text-format-text-variant').addClass('active');
}
if (attr == 'textDecoration') {
$('#text-textDecoration').val(text.getAttr(attr));
if (text.getAttr(attr) == 'underline')
$('.text-format-text-underline').addClass('active');
}
if (attr == 'fontStyle') {
$('#text-fontStyle').val(text.getAttr(attr));
if (text.getAttr(attr).indexOf('bold') > -1) {
$('.text-format-text-bold').addClass('active');
}
if (text.getAttr(attr).indexOf('italic') > -1) {
$('.text-format-text-italic').addClass('active');
}
}
}
}

I guess on your first stage load, the font is not loaded yet. So you need to wait until the font is loaded and then redraw a layer.
For the best solution you should use something like font observer:
How to be notified once a web font has loaded
Or you can simply redraw layer on timeout (but this solution is not perfect).

Related

how to color mat-header-cell dynamically according to values previously obtained from a service

I have this in my template
And this is my class component
ngOnInit(): void {
this.route.queryParamMap
.pipe(
concatMap(
params => {
this.añoUrl = Number(params.get('year'));
this.mesUrl = Number(params.get('mes'));
return this.generalService.getFestivosMes('leioa', this.añoUrl, this.mesUrl)
}
)
)
.subscribe(festivos => {
this.festivos = festivos;
}
)
}
colorColumna(columna: string): string {
var dia = new Date(this.añoUrl, this.mesUrl - 1, +columna.slice(1));
if (columna.slice(0, 1) == 'S' || columna.slice(0, 1) == 'D') {
return 'red'
}
if (this.festivos.find(f => new Date(f.fecha) == dia)) {
return 'red';
}
return 'green';
}
The problem is that when the function colorColumn() is executed this.festivos is empty.
But when the component is finished loading I have this.festivos
I don't know at what point in the component's life cycle I can access the service in order to have the return values available when the angular material table is rendered.
Any idea, please?
Thanks

Select2 - Show/Hide div based on selection

I am trying to have a div show if an option is selected using the Select2 plug in.
I tried using the following code but it does not work:
$(document).ready(function() {
var h = $(".shipment-details--other-description");
$("#shipment-details-select-pacakage-types").change(function() {
if (this.checked && this.value == "Other") {
h.show();
} else {
h.hide();
}
}).change()
});
The div is being hid but not being shown if the Other option is selected.
Is there a different way to do this with Select2?
Edit: Forgot to mention that this a multiple select field. Also, adjusted the code and took out the this.checked as that was for a check field.
try to create a new css class, is-hidden{ display:none;}
$(document).ready(function() {
var h = $(".shipment-details--other-description");
$("#shipment-details-select-pacakage-types").change(function() {
if (this.checked && this.value == "Other") {
h.addClass('is-hidden');
} else {
h.removeClass('is-hidden');
}
}).change()
});

Select no longer highlighting text on iPad (word)

In my add-in we navigate the document by calling select on either a paragraph or a search result from inside a paragraph. In the newest version of Word for iOS : 2.0.2 (170415) the document is scrolling to the correct part of the document but the text is no longer highlighting. This was working in the previous released version of word.
Oddly the text does highlight as expected if i open the search bar, and then navigate around my document.
public SelectTextInstance(text: string, paragraphIndex: number, textInstance: number) {
Word.run(function (context) {
// Create a proxy object for the paragraphs collection.
var paragraphs = context.document.body.paragraphs;
context.load(paragraphs, 'text,font');
return context.sync().then(function () {
if (paragraphIndex == -1) {//currently would occur for items that are inside of tables.
return;
}
var paragraph = paragraphs.items[paragraphIndex];
return context.sync().then(function () {
var ranges = null;
//256 is the maximum length for a search item. Longer than this and we just have to select the paragraph.
if (text != undefined && text != null && text.length <= 256) {
ranges = paragraph.search(text, { matchCase: true, ignoreSpace: true});
context.load(ranges, 'text');
}
return context.sync().then(function () {
if (ranges == null || ranges.items.length == 0) {
paragraph.select();
}
else {
//select the paragraph rather than overflow - something bad happened somewhere, so we'll fall back to highlighting the paragraph.
if (ranges.items.length <= textInstance) {
paragraph.select();
} else {
ranges.items[textInstance].select();
}
}
return context.sync().then(function () {
});
});
});
});
})
.catch(function (error) {
console.log('Error: ' + JSON.stringify(error));
if (error instanceof OfficeExtension.Error) {
console.log('Debug info: ' + JSON.stringify(error.debugInfo));
}
});
}
Thanks so much for reporting this. Effectively this is a regression. The range is selected but not colored. We will push the fix for the next update.

Display result matching optgroup using select2

I'm using select2 with Bootstrap 3.
Now I would like to know whether it is possible to display all optgroup items if the search matches the optgroup name while still being able to search for items as well. If this is possible, how can I do it?
The above answers don't seem to work out of the box with Select2 4.0 so if you're hunting for that, check this out: https://github.com/select2/select2/issues/3034
(Use the function like this: $("#example").select2({matcher: modelMatcher});)
function modelMatcher (params, data) {
data.parentText = data.parentText || "";
// Always return the object if there is nothing to compare
if ($.trim(params.term) === '') {
return data;
}
// Do a recursive check for options with children
if (data.children && data.children.length > 0) {
// Clone the data object if there are children
// This is required as we modify the object to remove any non-matches
var match = $.extend(true, {}, data);
// Check each child of the option
for (var c = data.children.length - 1; c >= 0; c--) {
var child = data.children[c];
child.parentText += data.parentText + " " + data.text;
var matches = modelMatcher(params, child);
// If there wasn't a match, remove the object in the array
if (matches == null) {
match.children.splice(c, 1);
}
}
// If any children matched, return the new object
if (match.children.length > 0) {
return match;
}
// If there were no matching children, check just the plain object
return modelMatcher(params, match);
}
// If the typed-in term matches the text of this term, or the text from any
// parent term, then it's a match.
var original = (data.parentText + ' ' + data.text).toUpperCase();
var term = params.term.toUpperCase();
// Check if the text contains the term
if (original.indexOf(term) > -1) {
return data;
}
// If it doesn't contain the term, don't return anything
return null;
}
Actually found the solution by modifying the matcher opt
$("#myselect").select2({
matcher: function(term, text, opt){
return text.toUpperCase().indexOf(term.toUpperCase())>=0 || opt.parent("optgroup").attr("label").toUpperCase().indexOf(term.toUpperCase())>=0
}
});
Under the premise that the label attribute has been set in each optgroup.
Found a solution from select2/issues/3034
Tested with select2 v.4
$("select").select2({
matcher(params, data) {
const originalMatcher = $.fn.select2.defaults.defaults.matcher;
const result = originalMatcher(params, data);
if (
result &&
data.children &&
result.children &&
data.children.length
) {
if (
data.children.length !== result.children.length &&
data.text.toLowerCase().includes(params.term.toLowerCase())
) {
result.children = data.children;
}
return result;
}
return null;
},
});
A few minor changes to people suggested code, less repetitive and copes when there are no parent optgroups:
$('select').select2({
matcher: function(term, text, opt){
var matcher = opt.parent('select').select2.defaults.matcher;
return matcher(term, text) || (opt.parent('optgroup').length && matcher(term, opt.parent('optgroup').attr("label")));
}
});

gmaps4rails show hide functionality

I'm hoping to get a little bit of insight on show / hide functionality in gmaps4rails.
example functionality
// == shows all markers of a particular category, and ensures the checkbox is checked ==
function show(category) {
for (var i=0; i<gmarkers.length; i++) {
if (gmarkers[i].mycategory == category) {
gmarkers[i].setVisible(true);
}
}
// == check the checkbox ==
document.getElementById(category+"box").checked = true;
}
// == hides all markers of a particular category, and ensures the checkbox is cleared ==
function hide(category) {
for (var i=0; i<gmarkers.length; i++) {
if (gmarkers[i].mycategory == category) {
gmarkers[i].setVisible(false);
}
}
// == clear the checkbox ==
document.getElementById(category+"box").checked = false;
// == close the info window, in case its open on a marker that we just hid
infowindow.close();
}
// == a checkbox has been clicked ==
function boxclick(box,category) {
if (box.checked) {
show(category);
} else {
hide(category);
}
// == rebuild the side bar
makeSidebar();
}
function myclick(i) {
google.maps.event.trigger(gmarkers[i],"click");
}
// == rebuilds the sidebar to match the markers currently displayed ==
function makeSidebar() {
var html = "";
for (var i=0; i<gmarkers.length; i++) {
if (gmarkers[i].getVisible()) {
html += '<a href="javascript:myclick(' + i + ')">' + gmarkers[i].myname + '<\/a><br>';
}
}
document.getElementById("side_bar").innerHTML = html;
}
So, in my controller, I'm building a list of markers, and including their categories as json.
#markersLoc = #locSearch.to_gmaps4rails do |loc, marker|
letter.next!
marker_image = "http://chart.apis.google.com/chart?chst=d_map_pin_letter&chld=#{letter}|82ABDD|000000"
marker.infowindow render_to_string(partial: '/events/info',
locals: {object: loc})
marker.picture({picture: marker_image,
width: 32,
height: 32,
marker_anchor: [11,30],
shadow_picture: "http://chart.apis.google.com/chart?chst=d_map_pin_shadow",
shadow_width: 110,
shadow_height: 110,
shadow_anchor: [12,34]})
marker.title loc.what
marker.sidebar render_to_string(partial: '/events/sidebar',
locals: {object: loc, letter: marker_image})
marker.json({cat: loc.category})
end
I'm kind of stuck, here. I know the :cat string is available (ex: 1,3,4), but I'm not sure how to use it to achieve what I'm after.
Was able to pretty much use what was there, with some modification. This gave me functionality to have 9 categories (could be more or less), and only view what I want. Awesome.
// == shows all markers of a particular category, and ensures the checkbox is checked ==
function show(category) {
var regEx = new RegExp("[" + category + "]")
for (var i=0; i<Gmaps.map.markers.length; i++) {
if (Gmaps.map.markers[i].cat) {
if (Gmaps.map.markers[i].cat.match(regEx)) {
Gmaps.map.showMarker(Gmaps.map.markers[i]);
}
}
}
// == check the checkbox ==
document.getElementById(category+"box").checked = true;
}
// == hides all markers of a particular category, and ensures the checkbox is cleared ==
function hide(category) {
var regEx = new RegExp("[" + category + "]")
for (var i=0; i<Gmaps.map.markers.length; i++) {
if (Gmaps.map.markers[i].cat) {
if (Gmaps.map.markers[i].cat.match(regEx)) {
Gmaps.map.hideMarker(Gmaps.map.markers[i]);
}
}
}
// == clear the checkbox ==
document.getElementById(category+"box").checked = false;
// == close the info window, in case its open on a marker that we just hid
// Gmaps.map.infowindow.close();
}
// == a checkbox has been clicked ==
function boxclick(box,category) {
if (box.checked) {
show(category);
} else {
hide(category);
}
}

Resources