I have a svg element, let's say a group, that has applied matrix rotation to it. I want to use svgmatrix api to flip it regarding root / screen axis.
Solution found as #enxaneta suggested, is to wrap element in a pristine group and apply the flipping to it, offloading the work math to the engine / browser. This way any transformations will be preserved
export const mirror = ($el, k) => {
if (!$el) return
// flip horizontall or vertical
if (k !== 1 && k !== -1) return false
// create a group from element
const $g = newtag('g')
const $father = $el.parentElement || $el.ownerSVGElement
const $next = $el?.nextElementSibling
$next
? $father.insertBefore($g, $next)
: $father.appendChild($g)
$g.appendChild($el)
// get matrix of group
let xg = m($g)
let bb = $g.getBBox()
let x = bb.x+bb.width/2
let y = bb.y+bb.height/2
if (k === -1) {
xg = xg.flipY().translate(0, -2*y)
} else if (k === 1) {
xg = xg.flipX().translate(-2*x, 0)
}
// apply transformations to the group
setm($g, xg)
// preserve transformations applied to group wrapped element
// so when will be extracted from group it will have them
const xel = m2e($el, $father)
$father.insertBefore($el, $g)
setm($el, xel)
$g.remove()
}
const m = e => e.transform.baseVal.consolidate()?.matrix || e.ownerSVGElement?.createSVGMatrix() || e.createSVGMatrix()
const setm = (e, m) =>e.transform.baseVal.initialize(e.ownerSVGElement?.createSVGTransformFromMatrix(m))
const newtag = (n, v=null) => {
n = document.createElementNS(xmlns, n);
n.setAttributeNS(null, 'id', '_'+rnd())
if (!v) return n
attr(n, v)
return n
}
const attr = (n, v=null) => {
for (let p in v){
n.setAttributeNS(null, p.replace(/[A-Z]/g, (m, p, o, s) => "-" + m.toLowerCase()), v[p])
}
}
const m2e = (a,e) => {
if (!e) e = a.ownerSVGElement
return e.getScreenCTM().inverse().multiply(a.getScreenCTM())
}
Related
I'm trying to get the quantity of for example: DragonBall, it would return x3 or Featured it would return x2 etc, however I have tried this method with just the spammed response of 2
let data = mockdata.forEach(function (i) {
count[i] = (count[i] || 0) + 1;
console.log(count[i] = (count[i] || 0) + 1)
});
[
'Daily',
'DragonBall1B',
'DragonBall2B',
'DragonBall3B',
'Featured',
'Featured2',
'SquadOrigins',
'SquadOrigins2'
]
API used to retrieve the above information:
https://fortnitecontent-website-prod07.ol.epicgames.com/content/api/pages/fortnite-game/shop-sections
A regular expression can remove the first instance of digits (along with whatever follows) to get you to the key you're interested in grouping on.
const mockdata = [
'Daily',
'DragonBall1B',
'DragonBall2B',
'DragonBall3B',
'Featured',
'Featured2',
'SquadOrigins',
'SquadOrigins2'
]
const count = {};
mockdata.forEach((str) => {
const key = str.replace(/\d+.*/, '');
count[key] = (count[key] || 0) + 1;
});
console.log(count.DragonBall);
const arr = [
'Daily',
'DragonBall1B',
'DragonBall2B',
'DragonBall3B',
'Featured',
'Featured2',
'SquadOrigins',
'SquadOrigins2'
]
const count = {};
arr.forEach((str) => {
const key = str.replace(/\d+.*/, "");
count[key] = (count[key] || 0) + 1;
});
let val = Object.entries(count);
let itemName;
let itemNum;
let result = [];
for (var i in val) {
itemName = val[i][0];
itemNum = val[i][1];
result += `${itemName} (x${itemNum})\n`;
}
console.log(result);
So I've managed to come up with some solutions to the following problems using backtracking. The problem is that they either get bottom 5% in terms of speed or I just run out of time.
They all follow a very familiar pattern in that they all use a closure backtrack function. This just happens to be my backtracking style and I'm very comfortable with this approach. I'm wondering if there's a way for me to memoize the solutions with just a few lines of code or if I have to completely rethink my brute force approach. I think the thing that I'm struggling with the most here is the shape of the memo data structure for each problem.
Note that I'm familiar with memoizing something as simple as the fibonacci sequence. Thanks! I think if I can get some help on this I'll be able to really take my problem solving to the next level.
https://leetcode.com/problems/word-break-ii/
var wordBreak = function(s, wordDict) {
const results = [];
const backtrack = (prefix, remaining, result) => {
if (!remaining.length) {
results.push(result.slice(0, -1));
}
const appending = remaining.slice(0, 1);
remaining = remaining.slice(1, remaining.length);
if (wordDict.includes(prefix + appending)) {
backtrack('', remaining, result + prefix + appending + ' ');
}
if (remaining) {
backtrack(prefix + appending, remaining, result);
}
}
backtrack('', s, '');
return results;
};
https://leetcode.com/problems/coin-change/
var coinChange = function(coins, amount) {
let min = Infinity;
const backtrack = (result, target) => {
if (target === 0) {
min = Math.min(result.length, min);
}
let i = coins.length - 1;
while (i >= 0) {
if (coins[i] <= target) {
backtrack([...result, coins[i]], target - coins[i]);
}
i--;
}
};
backtrack([], amount);
if (min === Infinity) return -1;
return min;
}
https://leetcode.com/problems/jump-game/
var canJump = function(nums) {
let flag = false;
const target = nums.length - 1;
const backtrack = index => {
if (index === target) {
flag = true;
return;
}
if (nums[index]) {
let n = nums[index];
while (n > 0) {
backtrack(index + n);
n--;
}
}
}
backtrack(0);
return flag;
};
https://leetcode.com/problems/palindrome-partitioning/
var partition = function(s) {
const results = [];
const backtrack = (prefix, str, result) => {
if (!str.length) {
results.push(result);
return;
}
const arr = str.split('');
prefix += arr.shift();
if (prefix.length === 1 || isPalindrome(prefix)) {
backtrack('', arr.join(''), [...result, prefix]);
}
if (arr.length) {
backtrack(prefix, arr.join(''), [...result]);
}
}
const isPalindrome = str =>
str === str.split('').reverse().join('');
backtrack('', s, []);
return results;
};
I'm using Konvajs, I have group of texts, and I want don't allow drag group outside of the canvas, I'm tried solved that using dragBoundFunc, but that don't help me, now I just try change group position during dragmove, but setPosition, setAbsloutePosition, nothing allow me to change group position
stage.on('dragmove', (e) => stageOnDragMove(e, layer));
const stageOnDragMove = (e: Konva.KonvaEventObject<any>, layer: Konva.Layer) => {
const selectionGroup = layer.findOne('#selection-group');
const transformer = layer.findOne<Konva.Transformer>('Transformer');
if (selectionGroup?.hasName('text-group')) {
const pos = selectionGroup.getClientRect({});
if (pos.x <= 0 || pos.y <= 0) {
selectionGroup.setAbsolutePosition({
x: 0,
y: 0
});
layer.draw();
}
}
transformer.attachTo(selectionGroup);
};
You can use this function to limit drag&drop and resize feature to limit its boundaries:
shape.on('dragmove transform', () => {
const box = shape.getClientRect();
const absPos = shape.getAbsolutePosition();
const offsetX = box.x - absPos.x;
const offsetY = box.y - absPos.y;
const newAbsPos = {...absPos}
if (box.x < 0) {
newAbsPos.x = -offsetX;
}
if (box.y < 0) {
newAbsPos.y = -offsetY;
}
if (box.x + box.width > stage.width()) {
newAbsPos.x = stage.width() - box.width - offsetX;
}
if (box.y + box.height > stage.height()) {
newAbsPos.y = stage.height() - box.height - offsetY;
}
shape.setAbsolutePosition(newAbsPos)
})
Demo: https://jsbin.com/rofupicupu/edit?html,js,output
I want to run the biconnected graph algorithm on a graph using GraphFrames running with pyspark 2.3.
I reaized that all the built in algorithms are running under the hood with GraphX in Scala.
Does there is a way that I can implement the biconnected algorithm in scala - GraphX and than call it on the GraphFrames object?
Is anyone familiar with an such a solution?
No, I am not familiar with any solution; I believe it cannot be done with those programs, best bet is to make your own program with JavaScript (preferably), check out three.js if you want easy 3D graphing, if not, just use SVG to graph various shapes, or even pure CSS, here is some JavaScript code for creating a line from two points, just use that with an array of points to draw the graph (there are two functions / classes included here, one being a helper function to create DOM nodes in general):
var Grapher = new (function() {
this.el = function(opts) {
if(!svgList.split(" ").find(x => x == opts.tag)) {
this.node = document.createElement(opts.tag || "div");
} else {
this.node = document.createElementNS('http://www.w3.org/2000/svg', opts.tag);
}
for(var k in opts) {
if(k == "style") {
for(var s in opts[k]) {
this.node.style[s] = opts[k][s];
}
} else if(k != "parent"){
this.node[k] = opts[k];
}
}
this.setAttrs = (attrs) => {
for(var k in attrs) {
this.node.setAttribute(k, attrs[k]);
}
};
this.getAttr = (at) => {
return this.node.getAttribute(at);
};
this.setStyle = (stl) => {
for(var k in stl) {
this.node.style[k] = stl[k];
}
}
var attr = opts.attr || {};
this.setAttrs(attr);
var optsPar = opts.parent;
var par = null;
if(optsPar) {
if(optsPar.constructor == String) {
par = f("#" + optsPar);
} else if(optsPar instanceof Element) {
par = optsPar;
}
}
this.parent = par || document.body || {appendChild: (d) => {}};
this.parent.appendChild(this.node);
};
this.line = (opts) => {
var start = opts.start || {x:0,y:0},
end = opts.end || {x:0,y:0},
rise = end.y - start.y,
run = end.x - start.x,
slope = rise / run,
boxWidth = Math.sqrt((rise * rise) + (run * run)),
degAngle = Math.atan(slope) * 180 / Math.PI,
thickness = opts.thickness || "2",
holder = new this.el({
attr: {
class:"lineBox"
},
style: {
position:"absolute",
left:start.x,
top:start.y,
width:`${boxWidth}px`,
height:`${thickness}px`,
transform:`rotate(${degAngle}deg)`,
transformOrigin:"0 0",
background:opts.texture || "black"
},
parent:opts.parent
});
}
})();
then to use the line function for graphing various lines (from point to point):
Grapher.line({
start: {
x:2,
y:200
}
end: {
x:10,
y:500
}
});
I want to get the string representation of a lambda Func<> Expression to get the Property Path. I have this example
Expression<Func<Employee, object>> _xxx = e => e.EmployeeInfo.Addresses["Address"];
and i am expecting a string
"EmployeeInfo.Addresses["Address"]"
when i do _xxx.ToString(); i'll just do some string parsing and i can get the result above.
My problem is when i do
var _addrName = "Address";
Expression<Func<Employee, object>> _xxx = e => e.EmployeeInfo.Addresses[_addrName];
i got a very long string
"EmployeeInfo.Addresses.get_Item(value(UnitTestProj.UnitTest.AnyTest+<>c__DisplayClass0)._addr)"
which is very hard to manipulate to come up with
"EmployeeInfo.Addresses["Address"]"
Is there any way to achieve my purpose?
TIA
This should get you pretty far - it's very hacky but I don't think there's a way around it:
Expression<Func<Employee, object>> _xxx = e => e.EmployeeInfo.Addresses[address];
WriteLine(ExprToString(_xxx)); //e.EmployeeInfo.Addresses[address]
_xxx = x => x.EmployeeInfo.Addresses["XYZ"];
WriteLine(ExprToString(_xxx)); //x.EmployeeInfo.Addresses["XYZ"]
_xxx = y => y.EmployeeInfo.Addresses[null];
WriteLine(ExprToString(_xxx)); //y.EmployeeInfo.Addresses[null]
_xxx = z => z.EmployeeInfo.Name;
WriteLine(ExprToString(_xxx)); //z.EmployeeInfo.Name
_xxx = z => z.EmployeeInfo.GetSalary();
WriteLine(ExprToString(_xxx)); //z.EmployeeInfo.GetSalary()
_xxx = z => z.EmployeeInfo.Addresses.Select(a => a.Street);
WriteLine(ExprToString(_xxx)); //z.EmployeeInfo.Addresses.Select(a.Street)
_xxx = z => z.EmployeeInfo.Array[3];
WriteLine(ExprToString(_xxx)); //z.EmployeeInfo.Array[3]
The implementation:
static string ExprToString(Expression expr)
{
switch (expr.NodeType)
{
case ExpressionType.Lambda:
//x => (Something), return only (Something), the Body
return ExprToString(((LambdaExpression) expr).Body);
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
//type casts are not important
return ExprToString(((UnaryExpression) expr).Operand);
case ExpressionType.Call:
//method call can be an Indexer (get_Item),
var callExpr = (MethodCallExpression) expr;
if (callExpr.Method.Name == "get_Item")
{
//indexer call
return ExprToString(callExpr.Object) + "[" + string.Join(",", callExpr.Arguments.Select(ExprToString)) + "]";
}
else
{
//method call
var arguments = callExpr.Arguments.Select(ExprToString).ToArray();
string target;
if (callExpr.Method.IsDefined(typeof (ExtensionAttribute), false))
{
//extension method
target = string.Join(".", arguments[0], callExpr.Method.Name);
arguments = arguments.Skip(1).ToArray();
}
else if (callExpr.Object == null)
{
//static method
target = callExpr.Method.Name;
}
else
{
//instance method
target = string.Join(".", ExprToString(callExpr.Object), callExpr.Method.Name);
}
return target + "(" + string.Join(",", arguments) + ")";
}
case ExpressionType.MemberAccess:
//property or field access
var memberExpr = (MemberExpression) expr;
if (memberExpr.Expression.Type.Name.Contains("<>")) //closure type, don't show it.
{
return memberExpr.Member.Name;
}
else
{
return string.Join(".", ExprToString(memberExpr.Expression), memberExpr.Member.Name);
}
}
//by default, show the standard implementation
return expr.ToString();
}