fabricjs IText - Clear Character Specific Styles - fabricjs

I need to be able to set the fontFamily for an entire IText object even if it has character specific styling (code example and jsfiddle below). Note, when changing the fontFamily the character-specific styles don't change. Is there a way for me to access and clear those styles and then apply the style to the entire set of characters?
http://jsfiddle.net/xmfw65qg/48/
var iTextSample = new fabric.IText('hello\nworld', {
styles: {
0: {
0: { textDecoration: 'underline', fontSize: 80 },
1: { textBackgroundColor: 'red' }
},
1: {
0: { textBackgroundColor: 'rgba(0,255,0,0.5)' },
4: { fontSize: 20 }
}
}
});

2020 May Edit
In later revisions of fabricJS, the method removeStyle(props) has been added.
That means you can do:
myTextObject.removeStyle('fontFamily');
to clean it up.
You also have:
myTextObject.cleanStyle('fontFamily');
That will instead remove all the fontaFamily properties that are duplicated of the main object. So that the style object is reduced in complexity if possible.
Original answer
http://jsfiddle.net/asturur/xmfw65qg/50/
you have to manually iterate the style object and clear the fontFamily property.
function setFont(name, value) {
var object = canvas.item(0);
if (!object) return;
if (object.styles) {
var styles = object.styles;
for (var row in styles) {
for (var char in styles[row]) {
if ('fontFamily' in styles[row][char]) {
delete styles[row][char]['fontFamily'];
}
}
}
}
object.set(name, value).setCoords();
canvas.renderAll();
}
why this is necessary is another matter.
I would open an issue on the github repository for that.
Edit:
As fabricjs released 1.6.2 a small bug that was causing the original style object to be changed during rendering, has been fixed.

Related

How to show .overlay with search results full width

var navbody: some View {
NavigationView {
ZStack {
somedarkcolorhere
List(searchModel.suggestions ?? [], rowContent: { text in
NavigationLink(destination: MediaSearchResultsView(searchText: text)) {
Text(text)
}
})
.overlay(SearchMediaHintsResultsScreen(searchModel: searchModel))
.searchable(text: $searchModel.searchText
// https://stackoverflow.com/questions/69668266/searchable-modifier-not-displaying-search-bar-below-navigation-bar-title
/* uncomment for search field to be shown initially and ever.
On iPad running 16.1 search field does show initially.
On iphone running 15.6.1 navigationTitle shows and search field
initially does not
*/
// , placement: .navigationBarDrawer(displayMode: .always)
)
.navigationTitle("v1_what_are_we_searching_for".localized)
}
.onChange(of: searchModel.searchText) { _ in
searchModel.processChangeOfSearchText()
}
.preference(key: ErrorPreferenceKey.self, value: observableError)
.sheet(isPresented: $observableError.showingError) {
ErrorView(error: observableError)
}
}
}
How to show .overlay with search results full width of the window?
currently it has gaps on the left and right
It is hard to see from just the code you have shown.
The List has default styling that includes some padding round the edges. You could try using a ForEach, or change the list style with a listStyle(.plain) modifier.
Does your overlay view also have a frame set to occupy the available space, such as .frame(maxWidth: .infinity)?
It may be due to the List default ListStyle of .insetGrouped. Try using .plain
Or try adding another view to the top layer of the ZStack that is only there when you want to show the overlay, so that it doesn't block List tap gestures, but can use the full View bounds to show the overlay.
i.e.
ZStack {
somedarkcolorhere
List { }
if showOverlay { Overlay }
}

FLOT crosshair working, but 'legends' needs to be re-initialized

All,
I am trying to have the crosshair track the three waveforms.
The crosshair does show up, and the tracking does not (oops ... see EDIT) take place. Please note - as specified in the picture - that the legend for the horizontal bar is simply a DIV styled to look like a legend from FLOT.
The CodePen can be found here
As the program is executed, the 'legend' becomes null, and the strings do not update ... the code is:
legends = $(".legendLabel");
legends.each(function () {
// fix the widths so they don't jump around
$(this).css('width', $(this).width());
});
I ended up having to put this code in the updateLegend() function. The question is 'why'? Am I sitting on a time bomb? :-) :-)
On a side note, thank you again to Raidri for getting me started earlier in the day.
-- EDIT -- The tracking DOES take place (I had managed to fix it in the middle of posting the question). The only doubt I have is about having to re-initialize variable 'legend' in function updateLegend()
-- EDIT 2 -- The code works in Chrome and Firefox, but fails in IE: 'Object doesn't support property or method "assign"'. I found the solution here
The code below will fix the problem ...
if (typeof Object.assign != 'function') {
Object.assign = function(target) {
'use strict';
if (target == null) {
throw new TypeError('Cannot convert undefined or null to object');
}
target = Object(target);
for (var index = 1; index < arguments.length; index++) {
var source = arguments[index];
if (source != null) {
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
}
return target;
};
}
$.each(data1, function (idx, item) {
Object.assign(item, {
stack: true,
lines: {show: false, steps: false },
bars: {show: true, horizontal:true, width: 1}
});
});

Famo.us RenderController not working under SequentialLayout?

I have added a common Surface and a Scrollview (actually a FlexScrollView) to a SequentialLayout and then added the layout to my View as the following code shows:
function _createCameraView() {
var layoutViews = [];
this.cameraView = new View({
size: [undefined, this.options.footerSize]
});
var layout = new SequentialLayout({
size: [undefined, this.options.footerSize],
direction: Utility.Direction.Y
});
var backgroundSurface = new Surface({
size: [undefined, 120],
content: 'some content',
classes : ['photo-guide-content'],
properties: {
backgroundColor: 'transparent',
zIndex: 4
}
});
// detail list
var detailsList = new FlexScrollView({
layout: ListLayout,
direction: Utility.Direction.X, // set direction to horizontal
paginated: true,
//autoPipeEvents: true,
useContainer: true,
container : {
size: [undefined, 60],
properties : {
'z-index' : 5,
}
}
});
layoutViews.push(backgroundSurface);
layoutViews.push(detailsList);
layout.sequenceFrom(layoutViews);
this.cameraView.add(alignModifier).add(layout);
}
Then I've added a RenderController on another view and I'm using it to display my cameraView like this:
function _selectCamera() {
if (!this.cameraView) {
_createCameraView.call(this);
}
this.footerRender.hide(this.mapView);
this.footerRender.show(this.cameraView);
}
I know I don't need to call the hide method from the render on the function above, just the show method and it should swap the views with a smooth opacity transition, which is defined by default. Although when using this Sequential Layout I'm not getting this effect. I know it has to do with this layout because I've tried to switch the layout to a FlexibleLayout and a GridLayout, and it works fine with these two. So, my question is, why doesn't work with the SequentialLayout? I've also noticed it has a method called setOutputFunction(outputFunction), is there a way to use it so the layout uses the opacity returned from the RenderController or how can it be fixed some other way?
Try adding a getSize method to your view.
Something like this:
this.cameraView.getSize = function() {
return [undefined, undefined];
};

jvectormap how to keep the current color when region is selected?

Here is my problem, i have a scale of colors for different countries. When I select a country, its color change and I don't want to.
I just want to use the stroke attribute (without the fill attribute) to display selected regions.
Problem is that the default color for fill is "yellow". I tried to set the fill attribute for selected region to "none" but it erases my current color when selected.
Have you guys a way to solve this issue?
$('#worldMap').vectorMap({
map: 'world_mill_en',
series: {
regions: [{
scale: ['#C1E712', '#5F7209'],
values: countryHitCounts,
}]
},
regionStyle: {
selected: {
fill: <= is there a keyword to not change the color when selected??
stroke: 'red',
"stroke-width": 1,
},
},
regionsSelectable: true,
selectedRegions: countrySelected,
onRegionSelected: function (event, code, isSelected, selectedRegions) {
//some code...
},
});
EDIT: in the minify js code source file, I changed the default style for selected region.
selected:{fill:"yellow"} by selected:{}
It works but if you have a better solution without changing the source file, I take it.
I ran into the same problem as well, what seemed to work for me was to override the selected fill with an invalid hex code. ex:
regionStyle: {
selected: {
fill: '#Z34FF9'
}
},
This seemed to register it as an override, but not actually apply it, leaving my original color.
You juste have to prevent the default action of the click :
,
onRegionClick: function(event, code){
event.preventDefault();
// your "some code" of region selected
}
Norrec's answer did not work for me, but I can override the class defaults just before creating the map. No source modification needed!
jvm.Map.defaultParams.regionStyle.selected = {};
map = new jvm.Map({
map: 'world_mill',
container: jQuery('#world-map'),
regionStyle: {
initial: {
fill: "#F6F6F6",
},
selected: {
stroke: '#FF00FF',
"stroke-width": 0.5,
}
},
}

YUI3 autocomplete has images on top - How to get autocomplete to the top

My auto YUI autocomplete zindex is off. How can I force the autocomplete DIV to the top.
Below I am using a standard template for YUI:
YAHOO.util.Event.onDOMReady(function(){
YUI().use("autocomplete", "autocomplete-filters", "autocomplete-highlighters", function (Y) {
var inputNode = Y.one('#name'),
tags = [
'css',
'css3',
'douglas crockford',
'ecmascript',
'html',
'html5',
'java',
'javascript',
'json',
'node.js',
'pie',
'yui'
],
lastValue = '';
inputNode.plug(Y.Plugin.AutoComplete, {
activateFirstItem: true,
minQueryLength: 0,
queryDelay: 0,
source: tags,
resultHighlighter: 'startsWith',
resultFilters: ['startsWith']
});
// When the input node receives focus, send an empty query to display the full
// list of tag suggestions.
inputNode.on('focus', function () {
inputNode.ac.sendRequest('');
});
// When there are new AutoComplete results, check the length of the result
// list. A length of zero means the value isn't in the list, so reset it to
// the last known good value.
inputNode.ac.on('results', function (e) {
if (e.results.length) {
lastValue = inputNode.ac.get('value');
} else {
inputNode.set('value', lastValue);
}
});
// Update the last known good value after a selection is made.
inputNode.ac.after('select', function (e) {
lastValue = e.result.text;
});
});
});
Simply to put the z-index in the css. Setting via JS used to be allowed, but as of YUI 3.4.0 it's a css-only flag (https://github.com/yui/yui3/blob/master/src/autocomplete/HISTORY.md).
The relevant CSS is (adjust your z-index as necessary):
.yui3-aclist { z-index: 100; }
PS., your YAHOO. line is from YUI2, so that is quite peculiar and definitely not a standard template.
By the time your callback in the YUI().use(...) section is called, the dom should be ready. No ondomready required.

Resources