I have two elements(rectangle, text), and when I move rentangle, the text move with the rentangle. enter image description here
After moving the rectangle, I want to select the text but I can not select it by clicking on it. How do I get the text is above the rectangle?
This is my code:
canvas.on("object:moving", function () {
//Objeto que se mueve
var obj = this.relatedTarget;
var type = obj.type;
var id = obj.id;
var top, left;
switch (type)
{
case 'rectangleElemento':
var elementos = buscarporElementoID(mapa.mapaElementos, id);
if (elementos.idTextoElemento != null)
{
var textoElemento = canvas.item(elementos.idTextoElemento);
top = obj.top + 20;
left = obj.left + 20;
textoElemento.setTop(top);
textoElemento.setLeft(left);
textoElemento.bringToFront();
canvas.bringForward(textoElemento);
//canvas.br
// obj.bringToBack();
//Pendiente que se active el texto por encima
}
break;
case 'textoElemento':
var elementos = buscarporElementoIDTexto(mapa.mapaElementos, id);
var bounds = canvas.item(elementos.idRectanguloElemento);
if (bounds.id == elementos.idRectanguloElemento) {
top = bounds.get('left');
left = bounds.get('top');
obj.setCoords();
if (!obj.isContainedWithinObject(bounds)) {
obj.setTop(goodtop);
obj.setLeft(goodleft);
// canvas.renderAll();
} else {
goodtop = obj.top;
goodleft = obj.left;
}
}
break;
}
});
Have you grouped the two objects to act as one or are you manipulating them separately?
I have done an older live exmple that loads an Image(t-shirt) and a logo(i-text) on it and we manipulate the text.
I have added textbox where we can update the i-text realtime and buttons to move the text up/down/left/right ,into the image element.
But first of all i create and group the two objects like this:
fabric.Image.fromURL(myImg, function(myImg) {
var img1 = myImg.scale(scaleFactor).set({ left: 0, top: 0 });
var text = new fabric.Text('the_text_sample\nand more', {
fontFamily: 'Arial',
fontSize:20,
});
text.set("top",myImg.height*scaleFactor-myImg.height*scaleFactor+150);
text.set("left",myImg.width*scaleFactor/2-text.width/2);
var group = new fabric.Group([ img1,text ], { left: 10, top: 10 });
canvas.add(group);
console.log(canvas._objects[0]._objects[1].text);
});
Live example : https://jsfiddle.net/tornado1979/zrazuhcq/
I hope that helps, good lick.
Related
This is what I'm trying to achieve:
So I have created 2 rounded buttons in a row and gave different background colors depending whether they're selected or not. The goal is to create a kind of an illusion of a tab/toggle.
The unselected button will have the same color as the row's background color. Unfortunately, since a row is a rectangle shape there comes a residue space at the corners that still shows the background color .
This is my code for the buttons
val cornerRadius = 20.dp
var selectedIndex by remember { mutableStateOf(0)}
val configuration = LocalConfiguration.current
val screenWidth = configuration.screenWidthDp.dp
val items = listOf(
OutlinedButton(onClick = { /*TODO*/ }) {
},
OutlinedButton(onClick = { /*TODO*/ }) {
})
Row(
modifier = Modifier
.padding(top = 8.dp)
.wrapContentHeight()
.width(screenWidth).background(color = Color.Gray).clip(shape = RoundedCornerShape(20.dp))
) {
// Spacer(modifier = Modifier.weight(1f))
items.forEachIndexed { index, item ->
OutlinedButton(modifier = Modifier
.wrapContentHeight()
.width(screenWidth/2),
shape = when (index) {
// left outer button
0 -> (if (selectedIndex == index) {
RoundedCornerShape(
topStart = cornerRadius,
topEnd = cornerRadius,
bottomStart = cornerRadius,
bottomEnd = cornerRadius
)
} else {
RoundedCornerShape(
topStart = cornerRadius,
topEnd = cornerRadius,
bottomStart = cornerRadius,
bottomEnd = cornerRadius
)
})
//rightouterbutton
else -> (if (selectedIndex == index) {
RoundedCornerShape(
topStart = cornerRadius,
topEnd = cornerRadius,
bottomStart = cornerRadius,
bottomEnd = cornerRadius
)
}
else{RoundedCornerShape(
topStart = 0.dp,
topEnd = cornerRadius,
bottomStart = 0.dp,
bottomEnd = cornerRadius
)})
},
border = BorderStroke(
1.dp, if (selectedIndex == index) {
Color.Transparent
} else {
Color.Transparent
}
),
colors = if (selectedIndex == index) {
// colors when selected
ButtonDefaults.outlinedButtonColors(
backgroundColor = Color.Yellow,
contentColor = Color.Black
)
} else {
// colors when not selected
ButtonDefaults.outlinedButtonColors(
backgroundColor = Color.Gray,
contentColor = Color.Black
)
},
onClick = { selectedIndex = index },
) {
if (index == 0) {
Text(
text = "In progress",
color = if (selectedIndex == index) {
Color.Black
} else {
Color.DarkGray.copy(alpha = 0.9f)
},
modifier = Modifier.padding(horizontal = 8.dp)
)
} else {
Text(
text = "Completed",
color = if (selectedIndex == index) {
MaterialTheme.colors.primary
} else {
Color.DarkGray.copy(alpha = 0.9f)
},
modifier = Modifier.padding(horizontal = 8.dp)
)
}
}
}
}
Modifier.clip applied after the Modifier.background has no effect in your case, you need to reverse the order. Read more about why the order of modifiers matters in this answer
.clip(shape = RoundedCornerShape(20.dp))
.background(color = Color.Gray)
Another option in the case of Modifier.background is that you can apply the shape specifically to the background color. Note that this solution will not clip other view content to the shape as Modifier.clip does, but in your case it fits.
.background(color = Color.Gray, shape = RoundedCornerShape(20.dp))
When uploading an image with image2 plugin, the height & width are initially set to the image's dimensions. Some of our users are uploading massive images and click OK to insert it onto the page without first choosing a reasonable size. The image fills the entire editor and they can't see what they're doing.
How can I set the initial size to something like 300px wide?
We're using CKEditor 4.11.1 with image2 plugin.
I was able to achieve this by hacking plugins/image2/dialog/image2.js and adding this to onChangeSrc() around line 148:
// Limit initial size
if (width > editor.config.image_initial_width) {
height = Math.round( editor.config.image_initial_width * ( height / width ) )
width = editor.config.image_initial_width;
}
if (height > editor.config.image_initial_height) {
width = Math.round( editor.config.image_initial_height * ( width / height) );
height = editor.config.image_initial_height;
}
and then defining config.image_initial_height=300 and config.image_initial_width=300.
But how can I achieve this without hacking?
Here's what worked for me.
Replace the image2 onChange event with our own, but keep a reference and call it.
Need to define two variables in config:
config.ckeditor_image2_initial_width = 300;
config.ckeditor_image2_initial_height = 300;
jQuery(document).ready(function() {
if (typeof CKEDITOR !== 'undefined') {
CKEDITOR.on('dialogDefinition', function(e) {
if (e.data.name == 'image2') {
var infoTab = e.data.definition.getContents('info');
var src_field = infoTab.elements[0].children[0].children[0];
var widthfield = infoTab.elements[2].children[0];
var height_field = infoTab.elements[2].children[1];
var src_was_changed = 0;
// Add a change function to the height field.
height_field.onChange = heightChanged;
// We need to add a change event to the src field but it already has
// one from image2 plugin. Replace it with our own but keep a reference
// and call it with CKEditor tools.
// https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_tools.html#method-override
src_field.onChange = CKEDITOR.tools.override(src_field.onChange, function(original) {
return function() {
// Call the original image2 onChangeSrc() function.
original.call(this);
var dialog = this.getDialog();
var widget_image_src = 0;
if (e.editor.widgets.selected.length) {
widget_image_src = e.editor.widgets.selected[0].data.src;
}
// Fire only when image src is set and has actually changed.
if (this.getValue() && (this.getValue() !== widget_image_src)) {
var initial_width = e.editor.config.ckeditor_image2_initial_width;
var initial_height = e.editor.config.ckeditor_image2_initial_height;
if (typeof initial_width !== 'undefined' || typeof initial_height !== 'undefined') {
// Set a flag to be used in heightChanged().
src_was_changed = 1;
}
}
}
});
// Change event for the image height field.
function heightChanged() {
if (src_was_changed) {
src_was_changed = 0;
var dialog = this.getDialog();
var initial_width = e.editor.config.ckeditor_image2_initial_width;
var initial_height = e.editor.config.ckeditor_image2_initial_height;
var width_field = dialog.getContentElement('info', 'width');
var height_field = dialog.getContentElement('info', 'height');
var new_width = orig_width = width_field.getValue();
var new_height = orig_height = height_field.getValue();
if (new_height > initial_height) {
new_height = initial_height;
new_width = Math.round(orig_width * (initial_height / orig_height));
}
if (new_width > initial_width) {
new_width = initial_width;
new_height = Math.round(orig_height * (initial_width / orig_width));
}
width_field.setValue(new_width);
height_field.setValue(new_height);
}
}
}
});
}
});
So I have a Flash ActionScript 2 code, which creates a preset amount of enemies, gives enemies stats, and makes them move around randomly. Code:
//Settings
var mapWidth:Number = 550;
var mapHeight:Number = 400;
var enemiesArray:Array = new Array();
var totalEnemies:Number;
var eClip:MovieClip;
//Math functions
function getdistance(x, y, x1, y1)
{
run = x1-x;
rise = y1-y;
return (hyp(run, rise));
}
function hyp(a, b)
{
return (Math.sqrt(a*a+b*b));
}
function resetDirection(mc:MovieClip)
{
mc.roamTime = random(50);
mc.t = mc.roamTime;
mc.roamDistance = random(60)+25;
mc.randomRoamDistanceX = (Math.random()*mc.roamDistance)+mc.xx-(mc.roamDistance/2);
mc.randomRoamDistanceY = (Math.random()*mc.roamDistance)+mc.yy-(mc.roamDistance/2);
mc.newRoamDistance = getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY);
mc.norm = mc.roamSpeed/mc.newRoamDistance;
mc.finalRoamDistanceX = (mc.randomRoamDistanceX-mc.xx)*mc.norm;
mc.finalRoamDistanceY = (mc.randomRoamDistanceY-mc.yy)*mc.norm;
}
//function to move enemies
function moveIt(mc:MovieClip)
{
//reduce roamTime;
mc.t--;
//move enemy to new position
if (getdistance(mc._x, mc._y, mc.randomRoamDistanceX, mc.randomRoamDistanceY)>mc.roamSpeed) {
mc._x += mc.finalRoamDistanceX;
mc._y += mc.finalRoamDistanceY;
}
//rotate enemy
XXXdiff = mc.xx-mc.randomRoamDistanceX;
YYYdiff = -(mc.yy-mc.randomRoamDistanceY);
rrradAngle = Math.atan(YYYdiff/XXXdiff);
if (XXXdiff<0) {
cccorrFactor = 270;
} else {
cccorrFactor = 90;
}
//
mc.ship_mc._rotation = -(rrradAngle*360/(2*Math.PI)+cccorrFactor);
//check if time to reset, based on roamTime
if (mc.t<=0) {
resetDirection(mc);
}
}
//
// Generate Enemies
//
// set and save enemy stats
//
//
// createEnemies(number of enemies you want, movieclip where you want to create the enemies);
//
function createEnemies(amount:Number, targetLocation:MovieClip) {
trace("createEnemies: "+amount);
for (var i = 0; i<amount; i++) {
randomXpos = Math.round(Math.random()*mapWidth);
randomYpos = Math.round(Math.random()*mapHeight);
//add new enemy to map
var newEnemy:MovieClip = targetLocation.attachMovie("enemy1", "enemy1_"+i, targetLocation.getNextHighestDepth());
enemiesArray.push(newEnemy);
//
//set enemy stats
newEnemy.id = i;
newEnemy._x = randomXpos;
newEnemy._y = randomYpos;
//save x and y position
newEnemy.xx = newEnemy._x;
newEnemy.yy = newEnemy._y;
//
newEnemy.roamSpeed = 2
newEnemy.roamTime = random(50);
newEnemy.roamDistance = random(60)+25;
newEnemy.t = 0;
//
newEnemy.myHealth = 10;
newEnemy.myName = "Small Scout";
//
resetDirection(newEnemy);
//target enemy
newEnemy.onPress = function() {
trace("Enemy: "+this.tName+" "+this.id);
target_txt.text = this.myName+": "+this.id+" Health: "+this.myHealth;
};
newEnemy.onEnterFrame = function() {
moveIt(this);
};
}
}
start_btn.onRelease = function() {
if (start_txt.text == "Start") {
//run the create enemies function to start the engine
createEnemies(box_mc.numberOfEnemies.text, map_mc);
//hide start button
start_txt._visible =false;
this._visible = false;
box_mc._visible = false;
}
};
I want program enemies to be grouped (based on fireflies algorithm). My idea is write for loop to define attractiveness, but I don't know how to make my objects move to the most attractiveness. Maybe someone would help me with this problem?
I change this line:
newEnemy.myHealth = 10;
on this
newEnemy.myHealth = Math.round(random(9)+1);
myHealth would be responsible for attractiveness. I try to use code from this site and modificate code to let objects with low attractiveness follow objects with large attractiveness. Also, I want to stop algorith, when they are in the groups.
My first post and I must admit that I'm bad at explaining stuffs. let me try.
I have this java code in spreadsheet which adds a UI, have certain checkboxes & a chart attached to UI.
When the first (EDC) checkbox is clicked range(C2) goes as true/false, changes the chart values in data.
Since the chart doesnt automatically update, I decided to remove the existing chart and add a new one. When the code is runned for first time...the UI is visible along with Populate charts, when I click checkbox the existing chart gets delete but the populate_chart function does not. Can any one help me??? Almost my first code (such big).
function Show_chart() {
var ss = SpreadsheetApp.getActive();
var calc = ss.getSheetByName("Calculations");
var data = calc.getRange(6, 19, 22, 2)
// var values = data.getValues()
// for (var row in values) {
// for (var col in values[row]) {
// Logger.log(values[row][col]);
// }
// }
var app = UiApp.createApplication().setHeight(600).setWidth(1200).setTitle("Attrition Report");
var mygrid = app.createGrid(7, 2)
var label1 = mygrid.setWidget(0, 0, app.createLabel("EDC Project"));
var label2 = mygrid.setWidget(1, 0, app.createLabel("Customer Project"));
var label3 = mygrid.setWidget(2, 0, app.createLabel("Support"));
var checkbox1 = mygrid.setWidget(0, 1, app.createCheckBox().setName("EDC"));
var checkbox2 = mygrid.setWidget(1, 1, app.createCheckBox().setName("CP"));
var checkbox3 = mygrid.setWidget(2, 1, app.createCheckBox().setName("Support"));
checkbox1.addClickHandler(app.createServerHandler("myClickHandler"));
var panel = app.createVerticalPanel();
panel.add(mygrid);
app.add(panel);
populate_charts()
ss.show(app);
}
function populate_charts(){
var ss = SpreadsheetApp.getActive();
var app = UiApp.getActiveApplication();
var calc = ss.getSheetByName("Calculations");
var data = calc.getRange(6, 19, 22, 2);
//1200 300
var chart = Charts.newLineChart().setDimensions(300, 100)
.setDataTable(data)
.build();
var chartpanel = app.createHorizontalPanel().setId("tbd");
chartpanel.add(chart);
return app.add(chartpanel);
}
function myClickHandler(e) {
var ss = SpreadsheetApp.getActive();
var calc = ss.getSheetByName("Calculations");
var app = UiApp.getActiveApplication();
// var data = calc.getRange(6, 19, 22, 2)
var chvalue = e.parameter.EDC;
calc.getRange("C2").setValue(chvalue);
var del = app.getElementById("tbd");
return app.remove(del);
populate_charts()
}
Thanks...
You should call populate_charts(); before return app.remove(del); in your function myClickHandler.
Whatever you add after returnin your function simply doesn't happen.
Don't delete an UiElement and recreate a new element with the same Id - very bad things will happen in UiApp, or GWT which is the mechanics behind UiApp.
You could simplify populate_charts:
function populate_charts(app, sSheet){
var data = sSheet.getSheetByName("Calculations").getRange(6, 19, 22, 2);
var chart = Charts.newLineChart().setDimensions(300, 100)
.setDataTable(data).build();
return chart;
}
myClickHandler could be reduced as well:
function myClickHandler(e) {
var app = UiApp.getActiveApplication();
var chvalue = e.parameter.EDC;
var sSheet = SpreadsheetApp.getActive();
sSheet.getSheetByName("Calculations").getRange("C2").setValue(chvalue);
app.getElementById("chartContainer").clear().add(populate_charts(app, sSheet));
return app;
}
The last 7 lines of Show_chart changed to:
app.add(mygrid.setId('grid'));
app.add(app.createFlowPanel()
.setId('chartContainer').add(populate_charts(app, ss)));
checkbox1.addClickHandler(
app.createServerHandler('myClickHandler')
.addCallbackElement(app.getElementById('grid'))
.addCallbackElement(app.getElementById('chartContainer')));
return app;
}
Don't forget to add all missing semicolons ; .
Chart is created by code. But I can't disable vertical lines in chart.
It is a code of creating chart:
public void CreateChart() {
CleanChart();
visiChart = new Chart()
{
ToolTipEnabled = true,
Width = 400,
Height = 200,
Padding = new Thickness(0),
Margin = new Thickness(0, 6, 0, -12),
Background = new SolidColorBrush(Colors.White),
};
ChartGrid grid = new ChartGrid()
{
Enabled = false
};
DataSeries dataSeries = new DataSeries();
DataPoint dataPoint;
Axis yAx = new Axis()
{
AxisLabels = new AxisLabels() { Enabled = false },
Grids = new ChartGridCollection() {grid}
};
int i = 0;
var deps = App.CurrentAgreement.Deposits.Deposit.Where(x => x.DepositIliv + x.DepositLink > 0).ToList();
foreach (var dep in deps) {
dataPoint = new DataPoint();
dataPoint.YValue = dep.DepositIliv + dep.DepositLink + dep.UValue + dep.WarrantyValue;
dataPoint.XValue = i;
i++;
dataPoint.LabelText = dataPoint.YValue.Out();
dataPoint.AxisXLabel = DateTime.Parse(dep.DepositDate).ToString("MMM yyyy");
dataPoint.MouseLeftButtonUp += dataPoint_MouseLeftButtonUp;
dataSeries.DataPoints.Add(dataPoint);
}
dataSeries.LabelEnabled = true;
dataSeries.RenderAs = RenderAs.Column;
dataSeries.Color = new SolidColorBrush(Colors.Green);
visiChart.Series.Add(dataSeries);
visiChart.AxesY.Add(yAx);
ChartPlaceHolder.Children.Add(visiChart);
}
But i dont need vertical lines visible. It is a screen of chart.
How i can disable lines??
Help me, please.
You have to disable the Grid lines from AxisX also.
Example:
ChartGrid grid = new ChartGrid()
{
Enabled = false
};
Axis xAx = new Axis();
xAx.Grids.Add(grid);
visiChart.AxesX.Add(xAx);