Joining intersecting paths in illustrator - javascript

Short term problem: I have three paths on an artboard. The end of one path has a point at the same position as the beginning of another. The other path is separate. They are all grouped. I have some code that loops through the pathsin the group, and if one path ends where another begins it tried to join them together. The group must be highlighted. To start with my artboard look like this (The top line is two paths):
An after the script is run it looks like this:
With a lot of points added to the end of the line underneath. Could someone lend me a hand with this, Ideally, I'd like it to look like this:
The code looks like this:
var doc = activeDocument;//Gets the active document
var numArtboards = doc.artboards.length;//returns the number of artboards in the document
var intersections = true
var group = doc.selection[0]
var paths = []
var intersecttions = 0
// Builds an array of all the paths in the grouped object
if (group !== undefined && group.pageItems.length >= 2) {
for (var i = 0; i < group.pageItems.length; i++) {
var item = group.pageItems[i];
if (item instanceof PathItem) {
item.id = 'Path No' + i;
paths.push(item)
}
}
}
//Sets the first path that will be added to
$.write('paths length ', paths.length,'\n')
var chain = paths[0]
var chainPoints = chain.pathPoints
var chainLength = chainPoints.length - 1
var c1 = chainPoints[0]
var c2 = chainPoints[chainLength]
$.write('c ', c1.anchor,':::', c2.anchor,'\n')
//loops through the paths in the group to see if any overlap the first past
for (var i = 1; i < paths.length-1; i++) {
var link = paths[i]
$.write(link, '\n')
var linkPoints = link.pathPoints
var linkLength = linkPoints.length - 1
$.write('l ', l1.anchor, ':::', l2.anchor, '\n')
if (toString(c1.anchor) === toString(l2.anchor)) {
$.write('inttersection', '\n')
$.write('link', link.id, '\n')
for (var j = 0; j < linkLength; ++j) {
chain.pathPoints.add(linkPoints[j])
$.write (linkPoints[j], '\n')
}
}
}

The first problem is that it's not detecting the instance of overlap correctly. The line:
if (toString(c1.anchor) === toString(l2.anchor)) {
is not comparing one string to another but comparing a true response with another true response. It should be:
if (String(c1.anchor) === String(l2.anchor)) {
you also have to pass across the attributes of each point you are adding to the line and remove the old line, so within the j loop you'll need to add the following
for (var j = 0; j < linkLength; ++j) {
var pp1 = chainPoints.add()
var p2i = linkPoints[j];
pp1.anchor = p2i.anchor;
pp1.rightDirection = p2i.rightDirection;
pp1.leftDirection = p2i.leftDirection;
pp1.pointType = p2i.pointType;
pp1.handle = p2i.handle;
}
link.remove();
This seems to work except that it doesn't add the last point of the second line. I'm guessing that the loop length may not be set correctly If I work it out I'll update the post. I found this in Hiroyuki Sato code for his JoinReasonable scripts http://shspage.com/aijs/en/

Related

Remove duplicate values from flat ARRAY

I'm wanting to remove duplicate values from the array tabData produced by the script below.
I've found numerous posts here that mention "removing duplicates from array", but don't seem to be relevant to my exact goal.
I've tried filter, I've tried using this answer and adjusting the variables to fit my script, but it did not remove the duplicates.
Surely there is a simple function that does exactly what I'm looking for, I'm just not finding it.
function getTabArray() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var version = ss.getRangeByName("version").getValue().toString();
var updateTabsName = "updateTabs";
var updateTabsSheet = ss.getSheetByName(updateTabsName);
var tabDataRows = updateTabsSheet.getLastRow();
var tabDataCols = updateTabsSheet.getMaxColumns() - 1;
var tabDataRange = updateTabsSheet.getRange(1, 2, tabDataRows, tabDataCols);
var tabData = tabDataRange.getValues(); // <-- REMOVE DUPLICATES
for (var i = 0; i < tabData.length; i++) {
if (tabData[0][i] != "" && tabData[0][i] > version) {
for (var j = 0; j < tabData.length; j++) {
if (tabData[j][i] != "" && j > 0) {
Logger.log("tabData[j][i] = " + tabData[j][i]); // tabData[j][i] = all values in column
}
}
}
}
}
This is the array it currently produces:
2.20200514.2,2.20200514.0,2.20200513.2,2.20200513.1,2.20200513.0,2.20200512.0,1.20200405.1,,tabDefinitions,Sheet6,Sheet6,changeLog,Sheet6,Index,,,,Sheet7,,Sheet7,settings,,,,Sheet8,,Sheet8,tabDefinitions,,,,,,,changeLog,,,,,,,updateTabs
I want to remove all duplicates (Sheet6, Sheet7, Sheet8, etc.) from the array.
EDIT:
After one more search, I found this answer which contains exactly what was answered below, but when I use any method in that answer, I still get all duplicates. Not sure what I'm doing wrong or not doing right.
var unique = tabData.filter((v, i, a) => a.indexOf(v) === i);
EDIT 2:
I realized my array was not actually "flat", so I added var tabData = tabDataRange.getValues().flat(); and now everything works!
You can use ES6 Set() function to remove the duplicates
const newArray = [...new Set(arrayWithDuplicates)];

Split javascript string into array

I have this javscript string:
response
"[[[#],[b,#],[b,w,b,b,b,#],[b,#],[b,w,w,b,#]],[[b,#],[b,b,#],[b,b,w,#],[b,b,b,#],[b,b,#]],[[b,#],[b,b,b,b,#],[b,w,#],[b,b,b,#],[b,#]],[[b,#],[b,#],[w,w,w,#],[b,b,w,w,#],[b,w,#]],[[b,#],[b,b,b,b,#],[b,w,b,#],[b,w,#],[b,b,#]]]"
This corresponds to a board game and which field (e.g [b,w,b,b,b,#]) is a cell with black and white pieces. The # is the top of the stack.
I need to parse this in order to create an array of tiles.
I have this:
XMLscene.prototype.readBoard = function(data){
var response = data.target.response;
console.log("REPONSE NO PARS" + response);
response = response.split("],");
console.log("REPONSE " + response);
response[0] = response[0].substring(1);
response[5] = response[5].substring(0, response[5].length - 2);
for(var i = 0; i < response.length; i++)
{
response[i] = response[i].substring(1);
response[i] = response[i].split("),");
for(var j = 0; j < response[i].length; j++)
response[i][j] = response[i][j].substring(5);
}
this.scene.board.loadTiles(response);
//this.scene.client.getPrologRequest('quit', 0, 1);
};
to be parsed in this function:
gameBoard.prototype.loadTiles = function(board){
console.log("BOARD : " + board);
this.tiles = [];
for (var i = 0; i < board.length; i++){
for (var j = 0; j < board[i].length; j++){
var player = board[i][j].split(",")[0];
console.log("PLAYER : " + player);
var type = board[i][j].split(",")[1];
console.log("Type : " + type);
if (type != "e") {
var tile = this.createTile(type, this.scene ,i*6 + j+100, player);
tile.line = i;
tile.col = j;
this.tiles.push(tile);
}
}
}
}
The board structure I want is something like this:
for the first stack: [#]
It's an empty cell
[b,#] - A cell with one piece - black
[b,w,w,b,#] - A cell with a black piece in the bottom, then two white pieces and a black on the top, therefore the black player is the owner of the stack!
The stack owner is the player that have his piece on the top of the stack (closest to #)
Is there any way to get an array with each stack being the element of it?
Regards
You could transform the data to JSON like this, ignoring the hashes as they seem to give information that is already known (the stack ends at the right):
var response = JSON.parse(response.replace(/,?#/g, '').replace(/[bw]/g, '"$&"'));
Then you can for instance identify the current player for a stack at (i, j), like this:
var player = board[i][j].slice(-1)[0]; // last element on the stack
Snippet:
// Sample data
var response = "[[[#],[b,#],[b,w,b,b,b,#],[b,#],[b,w,w,b,#]],[[b,#],[b,b,#],[b,b,w,#],[b,b,b,#],[b,b,#]],[[b,#],[b,b,b,b,#],[b,w,#],[b,b,b,#],[b,#]],[[b,#],[b,#],[w,w,w,#],[b,b,w,w,#],[b,w,#]],[[b,#],[b,b,b,b,#],[b,w,b,#],[b,w,#],[b,b,#]]]";
// Convert to nested array
var board = JSON.parse(response.replace(/,?#/g, '').replace(/[bw]/g, '"$&"'));
// Print the stack at 3, 3
console.log(board[3][3].join(','));
// Print player for that stack:
console.log(board[3][3].slice(-1)[0]);
A quick and dirty solution is to quote all your elements by using String.prototype.replace() and then put the entire result in an eval():
var str = "[[[#],[b,#],[b,w,b,b,b,#],[b,#],[b,w,w,b,#]],[[b,#],[b,b,#],[b,b,w,#],[b,b,b,#],[b,b,#]],[[b,#],[b,b,b,b,#],[b,w,#],[b,b,b,#],[b,#]],[[b,#],[b,#],[w,w,w,#],[b,b,w,w,#],[b,w,#]],[[b,#],[b,b,b,b,#],[b,w,b,#],[b,w,#],[b,b,#]]]";
var res = eval(str.replace(/[bw#]/g, "'$&'"));
console.log(res);
Modify your string to look like this...
var myString = '[[[#],[b,#],[b,w,b,b,b,#],[b,#],[b,w,w,b,#]],[[b,#],[b,b,#],[b,b,w,#],[b,b,b,#],[b,b,#]],[[b,#],[b,b,b,b,#],[b,w,#],[b,b,b,#],[b,#]],[[b,#],[b,#],[w,w,w,#],[b,b,w,w,#],[b,w,#]],[[b,#],[b,b,b,b,#],[b,w,b,#],[b,w,#],[b,b,#]]]'
replace elements with ""
Now run following:
var myArrayObject = JSON.parse(myString);
You just converted it to array.
Sample code:
https://fiddle.jshell.net/3gvzmwef/21/

3d Array Over-writing Values from other dimensions JS

I can't seem to figure out what I'm doing wrong on this code I wrote yesterday. This was my first time whipping up JavaScript, and using jQuery and Node.js also both for the first time, and I would think this three dimensional array should work as is. I've seen confusing mention about what multidimensional arrays are and people saying that JavaScript does not have any, though it has arrays of arrays. Anyways I guess I'm technically using an array of an array of an array, and don't understand why my outer array, which I imagined being an outer dimension by design, over-writes elements from the two inner-arrays into its own elements. The two inner arrays appear to work as they are supposed to, but the outter-most array mixes up the data in some way I don't really understand.
The inconsistency/problem can be observed by scrolling through the output.json file that is generated by this code and seeing that the outputs clearly do not match up with each of the three tables on this webpage I'm scraping from:
// My server.js file:
var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var app = express();
// the link below is a tutorial I was loosely following
// see http://scotch.io/tutorials/javascript/scraping-the-web-with-node-js
app.get('/scrape', function(req, res) {
url = 'http://espn.go.com/nba/player/stats/_/id/4145/kareem-abdul-jabbar'
request(url, function(error, response, html) {
if(!error) {
// utilize the Cheerio library on the returned html, yielding jQuery functionality
var $ = cheerio.load(html);
var numOfRows;
var stats = [[[]]];
for(var chart = 0; chart < 3; chart++) {
stats.push([[]]); // allocates space for each grid on each chart (each set of rows and columns)
$('.tablehead').eq(chart).filter(function(){
var data = $(this);
numOfRows = data.children().length - 2;
for(var i = 0; i < numOfRows + 1; i++) {
stats[chart].push([]); // allocates space for each row in the chart
}
})
var numOfColumns;
$('.stathead').eq(chart).filter(function(){
var data = $(this);
stats[chart][0][0] = data.children().first().text();
})
$('.colhead').eq(chart).filter(function(){ // first() specifies to select the first of the three occurances of this class; use eq(param) to find the Nth occurance
var data = $(this);
numOfColumns = data.children().length;
for(var i = 0; i < numOfColumns; i++) {
stats[chart][1][i] = data.children().eq(i).text();
}
})
var currentRow = 2;
for(var oddRow = 0; oddRow < (numOfRows + 1)/2 - 1; oddRow++) {
$('.tablehead .oddrow').eq(oddRow).filter(function(){
var data = $(this);
for(var c = 0; c < numOfColumns; c++) {
stats[chart][currentRow][c] = data.children().eq(c).text();
}
currentRow += 2;
})
}
currentRow = 3;
for(var evenRow = 0; evenRow < (numOfRows + 1)/2 - 1; evenRow++){
$('.tablehead .evenrow').eq(evenRow).filter(function(){
var data = $(this);
for(var c = 0; c < numOfColumns; c++) {
stats[chart][currentRow][c] = data.children().eq(c).text();
}
currentRow += 2;
})
}
currentRow -= 1; // gets the last allocated row index (after "currentRow += 2" has been executed)
$('.tablehead .total').eq(chart).filter(function(){
var data = $(this);
var LOGOIDX = 1;
for(var c = 0; c < numOfColumns - 1; c++) {
if(c < LOGOIDX) {
stats[chart][currentRow][c] = data.children().eq(c).text();
}
if(c == LOGOIDX) {
stats[chart][currentRow][c] = "N.A.";
stats[chart][currentRow][c + 1] = data.children().eq(c).text();
continue;
}
else {
stats[chart][currentRow][c + 1] = data.children().eq(c).text();
}
}
})
} // end chart loop
}
// Want to parse my json so that it displays in format: "name: value" rather than just "name" as it is now...
fs.writeFile('output.json', JSON.stringify(stats, null, 4), function(err){
console.log('File successfully written! - Check the project directory for the output.json file');
console.log('Number of columns in chart is: ' + numOfColumns);
})
// message to browser reminding that there's no UI involved here.
res.send('Check the console!')
})
})
app.listen('8081')
console.log('Magic happens on port 8081');
exports = module.exports = app;
Aha! Caught my bug -- just a simple logical error. Kind of embarrassing I didn't see it earlier, but oh well, got some practice and research (and a fair amount of distraction) by the end of the day:
As it can be seen, all the searching for HTML classes I did were parameterized by a variable named "chart", except for where I searched for odd rows and even rows within each chart -- the actual scraping of the bulk of each chart, so it naively appeared that my "3d array [was] over-writing values from other dimensions" <-- lol.
In simple, I just needed to create an offset based on a condition for each chart (a few extra lines of code), and I needed to edit two lines of code to reflect the newly calculated offset like so:
$('.tablehead .oddrow').eq(rowOffset + oddRow).filter(function(){
and
$('.tablehead .evenrow').eq(rowOffset + evenRow).filter(function(){
Thanks anyways for any help! I hope this issue tangentially benefits others greatly : P

string occurrences in a string

I'm am working on a script to count the number of times a certain string (in this case, coordinates) occur in a string. I currently have the following:
if (game_data.mode == "incomings") {
var table = document.getElementById("incomings_table");
var rows = table.getElementsByTagName("tr");
var headers = rows[0].getElementsByTagName("th");
var allcoord = new Array(rows.length);
for (i = 1; i < rows.length - 1; i++) {
cells = rows[i].getElementsByTagName("td");
var contents = (cells[1].textContent);
contents = contents.split(/\(/);
contents = contents[contents.length - 1].split(/\)/)[0];
allcoord[i - 1] = contents
}}
So now I have my variable allcoords. If I alert this, it looks like this (depending on the number of coordinates there are on the page):
584|521,590|519,594|513,594|513,590|517,594|513,592|517,590|517,594|513,590|519,,
My goal is that, for each coordinate, it saves how many times that coordinate occurs on the page. I can't seem to figure out how to do so though, so any help would be much appreciated.
you can use regular expression like this
"124682895579215".match(/2/g).length;
It will give you the count of expression
So you can pick say first co-ordinate 584 while iterating then you can use the regular expression to check the count
and just additional information
You can use indexOf to check if string present
I would not handle this as strings. Like, the table, is an array of arrays and those strings you're looking for, are in fact coordinates. Soooo... I made a fiddle, but let's look at the code first.
// Let's have a type for the coordinates
function Coords(x, y) {
this.x = parseInt(x);
this.y = parseInt(y);
return this;
}
// So that we can extend the type as we need
Coords.prototype.CountMatches = function(arr){
// Counts how many times the given Coordinates occur in the given array
var count = 0;
for(var i = 0; i < arr.length; i++){
if (this.x === arr[i].x && this.y === arr[i].y) count++;
}
return count;
};
// Also, since we decided to handle coordinates
// let's have a method to convert a string to Coords.
String.prototype.ToCoords = function () {
var matches = this.match(/[(]{1}(\d+)[|]{1}(\d+)[)]{1}/);
var nums = [];
for (var i = 1; i < matches.length; i++) {
nums.push(matches[i]);
}
return new Coords(nums[0], nums[1]);
};
// Now that we have our types set, let's have an array to store all the coords
var allCoords = [];
// And some fake data for the 'table'
var rows = [
{ td: '04.shovel (633|455) C46' },
{ td: 'Fruits kata misdragingen (590|519)' },
{ td: 'monster magnet (665|506) C56' },
{ td: 'slayer (660|496) C46' },
{ td: 'Fruits kata misdragingen (590|517)' }
];
// Just like you did, we loop through the 'table'
for (var i = 0; i < rows.length; i++) {
var td = rows[i].td; //<-this would be your td text content
// Once we get the string from first td, we use String.prototype.ToCoords
// to convert it to type Coords
allCoords.push(td.ToCoords());
}
// Now we have all the data set up, so let's have one test coordinate
var testCoords = new Coords(660, 496);
// And we use the Coords.prototype.CountMatches on the allCoords array to get the count
var count = testCoords.CountMatches(allCoords);
// count = 1, since slayer is in there
Use the .indexOf() method and count every time it does not return -1, and on each increment pass the previous index value +1 as the new start parameter.
You can use the split method.
string.split('517,594').length-1 would return 2
(where string is '584|521,590|519,594|513,594|513,590|517,594|513,592|517,590|517,594|513,590|519')

Javascript: matching a dynamic string against an array

I'm attempting to teach myself javascript. I chose something I assumed was simple, but ran into problems relatively quickly.
I'm attempting to search a string for another string given by the user.
My code so far is:
var source = "XREs2qqAQfjr6NZs6H5wkZdOES5mikexRkOPsj6grQiYNZfFoqXI4Nnc1iONKVrA";
var searchString = []; //the users input
searchString = prompt("Enter search string");
var hits = [];
var one = 0;
var two = 0;
var k = 0;
var sourceSearch = function(text) {
for(i = 0; i < source.length; i++) { //for each character in the source
if(source[i] === searchString[0]) { //if a character in source matches the first element in the users input
one = source.indexOf(i); //confused from here on
for(p = searchString.length; p > 0; p--) {
}
}
}
};
sourceSearch(searchString);
My idea was:
check to see if the first loop finds a character that matches the first character in the user input
if it matches, check to see if the next X characters after the first match the next X characters in the source string
if they all match, push them to the hits array
My problem: I have no idea how to iterate along the arrays without nesting quite a few if statements, and even then, that wouldn't be sufficient, considering I want the program to work with any input.
Any ideas would be helpful. Thanks very much in advance.
Note: There are a few un-used variables from ideas I was testing, but I couldn't make them work.
You can try:
if (source.indexOf(searchString) !== -1) {
// Match!
}
else
{
//No Match!
}
As the other answers so far point out, JavaScript strings have an indexOf function that does what you want. If you want to see how it's done "by hand", you can modify your function like this:
var sourceSearch = function(text) {
var i, j, ok; // always declare your local variables. globals are evil!
// for each start position
for(i = 0; i < source.length; i++) {
ok = true;
// check for a match
for (j = searchString.length - 1; ok && j >= 0; --j) {
ok = source[i + j] === searchString[j];
}
if (ok) {
// searchString found starting at index i in source
}
}
};
This function will find all positions in source at which searchString was found. (Of course, you could break out of the loop on the first success.) The logic is to use the outer loop to advance to each candidate start position in source and use the inner loop to test whether that position actually is the position of a match to searchString.
This is not the best algorithm for searching strings. The built-in algorithm is much faster (both because it is a better algorithm and because it is native code).
to follow your approach, you can just play with 2 indexes:
var sourceSearch = function(text) {
j = 0;
for(i = 0; i < source.length; i++) {
if(source[i] === text[j]) {
j++;
} else {
j = 0;
}
if (j == text.length) {
console.log(i - j); //this prints the starting index of the matching substring
}
}
};
These answers are all pretty good, but I'd probably opt for something like this:
var source = "XREs2qqAQfjr6NZs6H5wkZdOES5mikexRkOPsj6grQiYNZfFoqXI4Nnc1iONKVrA";
var searchString = []; //the users input
searchString = prompt("Enter search string");
var hits = source.split(searchString);
var hitsCount = hits.length - 1;
This way you have all of the data you need to figure out where each hit occurred in he source, if that's important to you.

Categories