Fill Shapes automatically with 5~ colors randomly in illustrator - adobe-illustrator

I have a mosaic of shapes fitted together in Illustrator however currently they're all black and white.
For example:
However, I've already got a series of colors that I want to use to fill each of the shapes in a random order (preferably without two colors being next to each other) so that it looks something like:
For example:
The mosaic is 250+ pieces in my first file and my second file has 800+ pieces.

/*
This script performs random color fill.
Select art items and colors in swatches panel and run script.
Note: neighbor art items can get the same colors.
*/
var doc = app.activeDocument;
var selItems = doc.selection;
var sw_sel = doc.swatches.getSelected();
if (sw_sel.lenght==0 )
exit;
for (var i=0; i<selItems.length; i++)
{
var selItem = selItems[i];
if(selItem.typename == "PathItem" ||
selItem.typename == "CompoundPathItem")
{
var randomColorIdx = getRandom(0, sw_sel.length - 1);
setColor(selItem, sw_sel[randomColorIdx].color);
}
}
function setColor(pItem, color)
{
pItem.filled = true;
if(pItem.typename == "PathItem")
pItem.fillColor = color;
else
pItem.pathItems[0].fillColor = color;
}
function getRandom(min, max)
{
return Math.floor(Math.random() * (max - min + 1)) + min;
}

There are a few plugins and scripts that can accomplish this.
Randomill is one such plugin and robotwood's 'Random Swatches Fill' script is another. With either one of these, you can use swatches from the swatches panel and randomly apply them to a set of objects.

Related

how do i update a Google Charts pie chart to reflect filtered data but retain filtered out segments as a diff colour

I'm new to Google Charts and I'm struggling to solve this.
I have a datatable (called "result" in the code)
Name Liquidity percent
a 1.3 20%
b 2.0 20%
c 3.4 20%
d 4 20%
e 5 20%
My pie chart is set to show 5 segments of equal size - 20% - and each segment is blue
I have set a 'Number Range Filter' control wrapper to filter the liquidity - when i set the control to the range 1 to 4 the pie moves to 4 equal sized segments.
BUT... I don't want it to do this. Instead of 1 segment disappearing I want the 5 segments to remain visible and the colour of the filtered segment to change to be a different colour.
The aim being that I can see visually a total percentage that falls within the number filter.
EDIT:
So I've had a mess about and this is as far as I've got incorporating dlaliberte's comment below.
function drawChart3(chartData3) {
var result = google.visualization.arrayToDataTable(chartData3,false); // 'false' means that the first row contains labels, not data.
var chart3 = new google.visualization.ChartWrapper({
'chartType': 'PieChart',
'containerId': 'chart3_div',
'dataTable': result,
'options': {
'width': 500,
'height': 500,
'legend': {position: 'none'},
'pieSliceText': 'none',
'colors': ['blue']
},
'view': {'columns': [0 , 1]}
});
var liquidityDT = new google.visualization.DataTable();
// Declare columns
liquidityDT.addColumn('number', 'Liquidity');
// Add data.
liquidityDT.addRows([
[1],
[2],
[3],
[4],
[5],
]);
// Create a range slider, passing some options
var liquidityRangeSlider = new google.visualization.ControlWrapper({
'controlType': 'NumberRangeFilter',
'containerId': 'filter3_div',
'dataTable': liquidityDT,
'options': {
'filterColumnLabel': 'Liquidity',
'minValue': 0,
'maxValue': 5
}
});
liquidityRangeSlider.draw();
chart3.draw();
google.visualization.events.addListener(liquidityRangeSlider, 'statechange', setChartColor);
function setChartColor(){
var state = liquidityRangeSlider.getState();
var stateLowValue = state.lowValue;
var stateHighValue = state.highValue;
for (var i = 0; i < result.getNumberOfRows(); i++) {
var testValue = result.getValue(i,2);
if (testValue < stateLowValue || testValue > stateHighValue){
alert("attempting to set colors")
//this bit I have no clue how to change the color of the table row currently being iterated on
chart3.setOption({'colors' : ['red']});
}
}
chart3.draw();
}
}
so it produces the pie chart with 5 blue segments. I can move the number filter and it fires the listener event but I can't get it to affect anything on the piechart (Chart3) - The code currently attempts just to change the whole chart to RED but that isn't even working never mind the just colouring the filtered segments
So how do I effect the changes into Chart3 and how do I only effect the filtered segments?.
any clues welcome?
thanks
You can (and must, for your application) use a NumberRangeFilter outside of a Dashboard because it will otherwise always do the data filtering. Instead, just listen for the change events on the NumberRangeFilter, get its current state, and then iterate through the colors array for your chart to set the appropriate colors. You'll have to draw the chart again with the updated colors. Here is the loop to set the colors and redraw.
var colors = [];
for (var i = 0; i < result.getNumberOfRows(); i++) {
var color = (testValue < stateLowValue || testValue > stateHighValue) ? 'red' : 'blue';
colors.push(color);
}
chart3.setOption('colors', colors);
chart3.draw();

epplus: How do I get a row's height after setting column's wraptext style to true?

After I set a column's WrapText=true, I want to see what the new height of the row will be (i.e. if the text wraps, for how many lines). It appears that the Height property of a row is not updated.
ExcelPackage pkg = new ExcelPackage();
ExcelWorksheet sheet = pkg.Workbook.Worksheets.Add("Test");
// height is 15.0
double heightBefore = sheet.Row(1).Height;
sheet.Cells[1, 1].Value = "Now is the time for all good men to come to the aid of their country";
ExcelColumn col = sheet.Column(1);
// this will resize the width to 60
col.AutoFit();
if (col.Width > 50)
{
col.Width = 50;
// this is just a style property, and doesn't actually execute any recalculations
col.Style.WrapText = true;
}
// so this is still 15.0. How do I get it to compute what the size will be?
double heightAfter = sheet.Row(1).Height;
// open the xls, and the height is 30.0
pkg.SaveAs(new System.IO.FileInfo("text.xlsx"));
In fact, a search for the Height property (or the underlying field _height) shows that it is only set by the property setter, and does not ever seem to be set based on anything else (like content in the row).
Any ideas on how I can get a refreshed Height for a row?
Thanks
The general pattern I've noticed with EPPlus is that it generates the framework of the document with the minimum amount of information necessary. Then, when you open the file, Excel fills out the remaining XML structure, which is why you always have to save the file after opening an EPPlus generated document.
For your question, I'm assuming that Excel is updating the row heights after you open the Excel file so EPPlus would not have the updated row height information. I'm not absolutely certain that the library doesn't support this, but like you I was unable to find a way to get the updated values.
One workaround however could be to just calculate what the value would be since you know your text length and column width:
ExcelPackage pkg = new ExcelPackage();
ExcelWorksheet sheet = pkg.Workbook.Worksheets.Add("Test");
// height is 15.0
double heightBefore = sheet.Row(1).Height;
var someText = "Now is the time for all good men to come to the aid of their country. Typewriters were once ground-breaking machines.";
sheet.Cells[1, 1].Value = someText;
ExcelColumn col = sheet.Column(1);
ExcelRow row = sheet.Row(1);
// this will resize the width to 60
col.AutoFit();
if (col.Width > 50)
{
col.Width = 50;
// this is just a style property, and doesn't actually execute any recalculations
col.Style.WrapText = true;
}
// calculate the approximate row height and set the value;
var lineCount = GetLineCount(someText, (int)col.Width);
row.Height = heightBefore * lineCount;
// open the xls, and the height is 45.0
pkg.SaveAs(new System.IO.FileInfo("text.xlsx"));
Here's the method to calculate the number of lines:
private int GetLineCount(String text, int columnWidth)
{
var lineCount = 1;
var textPosition = 0;
while (textPosition <= text.Length)
{
textPosition = Math.Min(textPosition + columnWidth, text.Length);
if (textPosition == text.Length)
break;
if (text[textPosition - 1] == ' ' || text[textPosition] == ' ')
{
lineCount++;
textPosition++;
}
else
{
textPosition = text.LastIndexOf(' ', textPosition) + 1;
var nextSpaceIndex = text.IndexOf(' ', textPosition);
if (nextSpaceIndex - textPosition >= columnWidth)
{
lineCount += (nextSpaceIndex - textPosition) / columnWidth;
textPosition = textPosition + columnWidth;
}
else
lineCount++;
}
}
return lineCount;
}
One thing to keep in mind is that Excel has a max row height of 409.5 so you'll want to make sure your column width is not so narrow that you'll reach this limit.
Also, another thing I noticed is that the column widths that you manually set with EPPlus don't actually set the columns to the expected value. For example, if you set your column width to 50, you'll notice that the actual column width is set to 49.29 so you may want to factor that in as well.

Adobe Edge Animate—how do I get the current label?

In Adobe Edge Animate, how do I get the name of the label that corresponds to a given time? I've seen that I can get the current time as an integer using
sym.getPosition()
but if there's a label at that position, how do I get the label as a string?
function getLabel() {
var stage = sym.getComposition().getStage();
var labels = stage.timelines['Default Timeline'].labels;
var currentLabel;
var currentPosition = stage.getPosition();
$.each( labels, function( label, position ){
if (position <= currentPosition) currentLabel = label;
});
return currentLabel;
}
console.log( getLabel() );
this will return the label on (or next previous to) the current position.
For those of us here looking for a Adobe Animate 2019 solution (like I was), it's similar, but slightly different:
function getLabel(_this) {
var currentLabel;
var currentPosition = _this.currentFrame;
_this.labels.forEach(function( label, index ){
if (label.position <= currentPosition) currentLabel = label.label;
});
return currentLabel;
}
Your position on the timeline is easier to get, and the labels object is organized differently. (Also jQuery is unavailable.)

How to add a text on top of a column with ZedGraph?

How can I add some text on top of a bar in a chart.
This is the code I have to add the bar:
var color = ColorTranslator.FromHtml(row.Colour);
var barItem = graphPane.AddBar(row.Propensity.ToString(), null, Ys.ToArray(), color);
Thank you
Here is a quick example using TextObj to simply add labels to each bar.
GraphPane myPane = zedGraphControl1.GraphPane;
double[] y = { 100, 50, 75, 125 };
BarItem myBar = myPane.AddBar("Data", null, y, Color.Red);
for (int i = 0; i < myBar.Points.Count; i++)
{
TextObj barLabel = new TextObj(myBar.Points[i].Y.ToString(), myBar.Points[i].X, myBar.Points[i].Y + 5);
barLabel.FontSpec.Border.IsVisible = false;
myPane.GraphObjList.Add(barLabel);
}
myBar.Label.IsVisible = true;
zedGraphControl1.AxisChange();
zedGraphControl1.Invalidate();
Of course this just uses the value of the data as the label. If you wanted to use custom labels, you could create a string array or list and use that inside the loop.
Here are some ZedGraph references:
Introduction and examples: http://www.codeproject.com/KB/graphics/zedgraph.aspx
Source code documentation: http://zedgraph.sourceforge.net/documentation/default.html
You need to define AlignH and AlignV in your text object:
TextObj textLabel = new TextObj(value.ToString(), positionX, value, CoordType.AxisXYScale, AlignH.Center, AlignV.Top);
AlignV define the position of your value on the bar.
Providing you want the label text to match the value of each bar, then you can do it with a single line of code:
BarItem.CreateBarLabels(graphPane, false, "F0");
Note that the 3rd parameter is a double.ToString format. e.g. "F0" = 12, "F2" = 12.34
However, if you want any flexibity with it then this solution is not ideal. It also doesn't work very well if you have a stacked bar chart, because having any 0 value data will cause labels to overlap and look horrific

How to automate vertical scrolling in Flex AdvancedDataGrid when dragging item below bottom of visible rows?

I have an AdvancedDataGrid with XML dataProvider. Drag and drop in enabled, and works within the visible rows of the ADG.
HOWEVER, if I attempt to drag an item past the bottom-most visible row of the ADG, the ADG does NOT scroll to display the next rows, which makes it impossible to drag and drop beyond the immediately visible rows. Although this would seem to be logical default behaviour of a datagrid (drag to bottom and keep dragging to reveal subsequent rows), Flex evidently doesn't Do Things That Way. I'm flummoxed how to implement this programatically.
Can anyone help?
I had to do this with a few items in the past, basically what I did was monitor the mouses Y position in the DG, if it was 50 or fewer pixels from the top or bottom then I would set the verticalscrollposition of the DG += 20 or -= 20 as required.
Let me know if you need a code snip but you should be able to figure out how to do all of this.
this worked for me, from Andre's solution but also checking for maxVerticalScrollPosition
and i was extending the ADG
protected function onDragOver(event:DragEvent):void
{
var dropIndex:int = calculateDropIndex(event);
autoScoll(dropIndex);
}
//to have the adg scroll when dragging
//http://stackoverflow.com/questions/2913420/how-to-automate-vertical-scrolling-in-flex-advanceddatagrid-when-dragging-item-be
protected function autoScoll(dropIndex:int):void
{
var rowsDisplayed:Number = rowCount;
var topvisibleIndex:int = verticalScrollPosition;
var botvisibleIndex:int = topvisibleIndex + rowsDisplayed;
if (dropIndex <= topvisibleIndex)
{
verticalScrollPosition = Math.max(verticalScrollPosition - 1, 0);
}
else if (dropIndex >= botvisibleIndex - 1 && dropIndex < (rowCount + maxVerticalScrollPosition - 1))
{
verticalScrollPosition += 1;
}
}
Got to love Flex, man. Where the obvious stuff takes a ton of time.
So this is what I ended up doing:
mygrid.addEventListener( DragEvent.DRAG_OVER, handleDragOver);
public function handlerDragOver(event:DragEvent):void{
var dropIndex:int = mygrid.calculateDropIndex(event);
var rowsDisplayed:Number = mygrid.rowCount;
var topvisibleIndex:int = mygrid.verticalScrollPosition;
var botvisibleIndex:int = topvisibleIndex + rowsDisplayed;
if ( dropIndex <= topvisibleIndex) {
mygrid.verticalScrollPosition = Math.max( mygrid.verticalScrollPosition- 1, 0 );
} else if( dropIndex >= botvisibleIndex - 1 ){
mygrid.verticalScrollPosition += 1;
}
}