How to solve a special "select and transform: resize text" problem? - konvajs

1. Background:
I use konvajs to create a "table" component:
structure:
Stage
|
Layer
|
+-----+--------------+
| |
Group(tableGroup) Group(tableGroup)
|
+--------------+--------+
| |
Group(cellGroup) Group(cellGroup)
|
+----+----+
| |
Shape(Rect) Shape(Text)
image:
table component
2. Target:
I want every text shape to be width adaptive.
I found it in the official documents of konvajs:
How to change width of the text with transforming tool? https://konvajs.org/docs/select_and_transform/Resize_Text.html
Scenario 1: add all "cellGroup" to "transformer"
// My code
tableGroup.on('click', function (e) { // Click the selected table
tr.nodes([])
tableGroup.getChildren().map(function(item) {
tr.nodes(tr.nodes().concat(item)); // Add all cellGroups to transformer
item.off('transform')
item.on('transform', (e) => {
item.setAttrs({
width: item.width() * item.scaleX(),
height: item.height() * item.scaleY(),
scaleX: 1,
scaleY: 1,
});
item.getChildren().map(function(child){
child.setAttrs({
width: item.width() * item.scaleX(),
height: item.height() * item.scaleY(),
scaleX: 1,
scaleY: 1,
});
})
})
})
});
Scheme 2: add "tablegroup" to "transformer"
// My code
tableGroup.on('click', function (e) { // Click the selected table
tr.nodes([tableGroup]) // Add all tableGroup to transformer
tableGroup.on('transform', (e) => {
tableGroup.getChildren().map(function(item) {
item.setAttrs({
width: item.width() * item.scaleX(),
height: item.height() * item.scaleY(),
scaleX: 1,
scaleY: 1,
});
item.getChildren().map(function(child){
child.setAttrs({
width: item.width() * item.scaleX(),
height: item.height() * item.scaleY(),
scaleX: 1,
scaleY: 1,
});
})
})
})
});
conclusion: Scheme 1 is feasible, but scheme 2 is not.My requirement is to add "tableGroup" to transformer and realize text width adaptation.Find a solution, thank you very much.
3. Other:
Q: Why must "tableGroup" be added to "transformer"?
A: Because when moving a "Group" or "Shape" with "Transformer", the coordinates (x, y) of the "Group" or "Shape" will be changed. I don't want to change the coordinates of "cellGroup", I want to change the coordinates of "tableGroup" (x, y). Or you have a better solution.Find a solution, thank you very much.

Here is a solution using two groups - one for the table outline and a second to contain the cells. The cell group has its attrs set to follow the table group as it is transformed - excluding the scale!
This is not a perfect solution that you can cut & paste as a usable component but should show you a potential alternative.
/*
* From here onwards we set up the stage and its contents.
*/
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
}),
layer = new Konva.Layer(),
tblGroup = new Konva.Group({draggable: true}),
cellGroup = new Konva.Group(),
cellRect = new Konva.Rect({strokeWidth: 1, stroke: 'black', name: 'cellRect'}),
cellText = new Konva.Text({fontName: "Arial", fontSize: 20, fill: 'black', name: 'cellText'}),
tr = new Konva.Transformer();
stage.add(layer);
layer.add(tr);
// Using this plain JS objet to define the table and relative cell positions.
const tblData = {
position: { x: 100, y: 100, width: 202, height: 82},
cells: [
{x: 1, y: 1, width: 100, height: 40, text: 'Cell 1-1'},
{x: 101, y: 1, width: 100, height: 40, text: 'Cell 1-2'},
{x: 1, y: 41, width: 100, height: 40, text: 'Cell 2-1'},
{x: 101, y: 41, width: 100, height: 40, text: 'Cell 2-2'},
]
}
const tableGroup = tblGroup.clone({x: tblData.position.x, y: tblData.position.y}),
tblPosGroup = tableGroup.clone(), // position exactly as tableGroup.
tblRect = cellRect.clone({x:0, y: 0, width: tblData.position.width, height: tblData.position.height});
tblRect.stroke('red');
tableGroup.add(tblRect);
// add the cells.
for (let i = 0; i < tblData.cells.length; i++){
const
cell = cellGroup.clone({}),
rect = cellRect.clone(tblData.cells[i]),
text = cellText.clone(tblData.cells[i]);
// Note we stach the positioning data into the Konva shape instances in a custom attr - used in the transform event
rect.setAttrs({posData: tblData.cells[i]});
text.setAttrs({posData: tblData.cells[i]});
cell.add(rect,text);
tblPosGroup.add(cell);
}
layer.add(tableGroup, tblPosGroup);
tableGroup.on('transform', (e) => {
// make the cells group follow the tbl group as it is transformed
tblPosGroup.setAttrs({position: tableGroup.position(), rotation: tableGroup.rotation()});
// find all the objects we want to manager - using the shape name() attr which we search with a dot prefix.
tblPosGroup.find('.cellRect, .cellText').map(function(item) {
const cellPos = item.getAttr("posData");
// set the position and size of the cells referring to original position & size data and applying scale from transformer.
item.setAttrs({
x: cellPos.x * tableGroup.scaleX(),
y: cellPos.y * tableGroup.scaleY(),
width: cellPos.width * tableGroup.scaleX(),
height: cellPos.height * tableGroup.scaleY()
});
})
})
tblPosGroup.on('click', function (e) { // When the table is clicked - actually we listen on the cells group as this will get the click
tr.nodes([tableGroup]); // Add all tableGroup to transformer
e.cancelBubble = true;
})
stage.on('click', function (e) {
tr.nodes([]);
})
body {
margin: 20px;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}
<script src="https://unpkg.com/konva#8/konva.min.js"></script>
<p>A table-like construction. The aim was to keep cell contents unchanged in size and scale whilst allowing a transformer to be used.</p>
<p>Solution is two groups. Group#1 is the main table rect and group#2 is the cells. Group#2 attrs are set to follow group#1 attrs in the group#1.onTransform event listener.</p>
<div id="container"></div>

Related

how would I turn a "magic-wand" selection into a path object in GIMP using batch scripting

As the title suggest, how would one perform this?
Right now I have this plugin to add a basic path to an image, but how do I convert a selection from "gimp-image-select-contiguous-color" into "vectors"?
#!/usr/bin/env python
from gimpfu import pdb, main, register, PF_STRING
def add_path(infile, outfile):
image = pdb.gimp_file_load(infile, 'image')
vectors = pdb.gimp_vectors_new(image, 'clippath')
w = image.width
h = image.height
path = [
# The array of bezier points for the path.
# You can modify this for your use-case.
# This one draws a rectangle 10px from each side.
# Format: control1-x, control1-y, center-x, center-y, control2-x, control2-y
100, 100, 100, 100, 100, 100,
w - 100, 100, w - 100, 100, w - 100, 100,
w - 100, h - 100, w - 100, h - 100, w - 100, h - 100,
100, h - 100, 100, h - 100, 100, h - 100
]
pdb.gimp_vectors_stroke_new_from_points(vectors, 0, len(path), path, True)
pdb.gimp_image_add_vectors(image, vectors, 0)
drawable = pdb.gimp_image_get_active_layer(image)
pdb.file_tiff_save(image, drawable, outfile, 'image.tif', 0)
args = [(PF_STRING, 'infile', 'GlobPattern', '*.*'), (PF_STRING, 'outfile', 'GlobPattern', '*.*')]
register('python-add-path', '', '', '', '', '', '', '', args, [], add_path)
main()
See pdb.plug_in_sel2path(image, drawable) (drawable can be None) or pdb.plug_in_sel2path_advanced(...) (better use the first one for you sanity).
They don't return anything but the created path is the first one (image.vectors[0]).

FabricJS in Vaadin 12 project

I want to use FabricJS to draw shapes in an existing vaadin 12 project, but the shapes not showing.
test-design-1.html file:
<div id="divCanvas">
<canvas id="c" height="800px" width="800px"> </canvas>
</div>
TestDesign1.java file:
#Tag("test-design-1")
#JavaScript("src/views/js/jquery.min.js")
#JavaScript("src/views/js/fabric.js")
#JavaScript("src/views/js/1.js")
#HtmlImport("src/views/test-design-1.html")
1.js file:
window.onload = function() {
let canvas = new fabric.Canvas('c');
alert('Objects count: ' + canvas._objects.length); //0
let rect = new fabric.Rect({
left: 100,
top: 100,
width:190,
height:240,
strokeWidth: 1,
stroke:'red',
fill:'green'
});
canvas.add(rect);
alert('Objects count: ' + canvas._objects.length); //1
canvas.renderAll();
}
After running, "Objects count: 1" pop up, but the rectangle shape not showing.
How can I solve this?

D3 Pie Chart too dented

I am getting as a result a badly rendered pie chart. Why is this happening? Am I doing smth wrong? What can I do to have a better border? I am corrently using v3.5.17.
var w = 500,
h = 500;
//var data = [10, 80, 50, 60, 30, 42, 27, 77];
var max = d3.max(data);
var min = d3.min(data);
var color = d3.scale.ordinal().range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b", "#a05d56", "#d0743c", "#ff8c00"]);
console.log(color(50));
var canvas = d3.select("#piegraphic").append("svg")
.attr("width", w)
.attr("height", h);
var group = canvas.append("g")
.attr("transform", "translate(200, 200)");
var r = 150;
var arc = d3.svg.arc()
.outerRadius(r - 10)
.innerRadius(0);
var arc2 = d3.svg.arc()
.outerRadius(r + 10)
.innerRadius(0);
var pie = d3.layout.pie()
.value(function (d) {
return d.count;
});
var arcs = group.selectAll(".arc")
.data(pie(data))
.enter()
.append("g")
.attr("class", "arc");
var asdf = arcs.append("path")
.attr("d", arc)
.attr("fill", function (d) {
return color(d.data);
})
asdf.on("mouseover", function (d) {
d3.select(this).transition().duration(200).attr("d", arc2);
});
asdf.on("mouseout", function (d, i) {
d3.select(this).transition().duration(200).attr("d", arc);
});
var circle = group.append("circle")
.attr({
"cx": 0,
"cy": 0,
"r": 140,
"fill": "none",
"stroke": "#fff",
"stroke-width": 2
});
I tried other approaches but I always getting the same result I dont know what else I can try. Thanks in advance
EDIT
My data looks like this :
[{count:106136313.3, label : "RR" },{count:136313.3, label : "RA" },{count:1061313.3, label : "TE" }]

Why doesn't PageComponent respect the right contentInset

This is taken (almost) verbatim from PageComponent example (minus the imported Sketch doc), yet in my code, the right contentInset is totally ignored and the cards are offset strangely on each card after the first.
# Set-up PageComponent
page = new PageComponent
width: Screen.width
height: Screen.height
y: 0
scrollVertical: false
contentInset: {top: 32, left: 32, right: 32}
backgroundColor: "pink"
# Variable that adjusts the amount of cards
amount = 4
print page.width
print screen.width
# Create and style the cards within a loop
for i in [0...amount]
card = new Layer
backgroundColor: "#fff"
borderRadius: 8
width: page.width - 64
height: 1040
x: page.width * i
superLayer: page.content
card.style.boxShadow = "0 1px 6px rgba(0,0,0,0.2)"
I'm using Framer Studio ver 1.13.25 (1583)
Seems to be a bug in one of the latest versions of the framerjs library.
You can overpass the bug by putting every page inside a full width wrapper.
Check here a fixed example: http://share.framerjs.com/z09x27iqjce1/​
I hope it helps :)

Highcharts with datatable

There is an example for highcharts:
http://jsfiddle.net/highcharts/z9zXM/
However I couldn't reverse x axis and y axis at table. I mean I want it like:
Tokyo Jan Feb ..
New York
Berlin
London
Also I want to locate that table at middle under chart.
Any ideas?
This is how the loops should be:
// draw category labels
$.each(series, function(serie_index, serie) {
renderer.text(
serie.name,
cellLeft + cellPadding,
tableTop + (serie_index + 2) * rowHeight - cellPadding
)
.css({
fontWeight: 'bold'
})
.add();
});
$.each(chart.xAxis[0].categories, function(category_index, category) {
cellLeft += colWidth;
// Apply the cell text
renderer.text(
category,
cellLeft - cellPadding + colWidth,
tableTop + rowHeight - cellPadding
)
.attr({
align: 'right'
})
.css({
fontWeight: 'bold'
})
.add();
$.each(series, function(i) {
renderer.text(
Highcharts.numberFormat(series[i].data[category_index].y, valueDecimals) + valueSuffix,
cellLeft + colWidth - cellPadding,
tableTop + (i + 2) * rowHeight - cellPadding
)
.attr({
align: 'right'
})
.add();
});
});
Here is the link: http://jsfiddle.net/pJ3qL/1/
Then you should draw the table borders inside the loops again if you want ;)

Resources