I pared down some odd behavior I was experiencing in SVG and I came up with this test case:
<circle r="10" />
<rect width="18" height="18" />
<polygon points="10,20 30,30 40,15 25,10" />
<script>
var svg = document.querySelector('svg'),
els = document.querySelectorAll('svg *');
for (var i=els.length;i--;){
var el = els[i];
el._dragXForm = el.transform.baseVal.appendItem(svg.createSVGTransform());
setInterval((function(el){
return function(){
var tx = el._dragXForm.matrix;
tx.e += Math.random()*2-1;
tx.f += Math.random()*2-1;
}
})(el),50);
}
</script>
In Safariv5 and Chromev18 on OS X the circle and polygon both jitter, but the rect does not. It does nothing. The SVGMatrix is getting a new value, but the appearance on screen is not updated. (In Firefox, it works as expected.)
If I change the script to remove _dragXForm like so:
for (var i=draggables.length;i--;){
var el = draggables[i];
el.transform.baseVal.appendItem(svg.createSVGTransform());
setInterval((function(el){
return function(){
var tx = el.transform.baseVal.getItem(0).matrix;
tx.e += Math.random()*2-1;
tx.f += Math.random()*2-1;
}
})(el),50);
}
…then the <rect> moves along with the others.
Besides seeming like an insane bug (how can this only affect a <rect>?!) I feel that this has not yet isolated the source of the bug.
What's the simplest possible code that can reproduce this odd behavior? (And if there's already a bug filed for this, I'd love to know about it.)
This code appears to be getting closer to the heart of the matter:
var svg = document.querySelector('svg'),
els = document.querySelectorAll('svg *');
for (var i=els.length;i--;){
var el = els[i],
tx = el.transform.baseVal.appendItem(svg.createSVGTransform());
console.log( el.tagName, tx===el.transform.baseVal.getItem(0) );
setTimeout((function(el,tx){
return function(){
console.log( el.tagName, tx===el.transform.baseVal.getItem(0) );
}
})(el,tx),1);
}
Output:
polygon true // The return value of appendItem is the same as the first item
rect true // The return value of appendItem is the same as the first item
circle true // The return value of appendItem is the same as the first item
polygon true // The returned value is STILL the same as the first item
rect false // The returned value is NO LONGER the same as the first item
circle true // The returned value is STILL the same as the first item
Related
By default, the cursor is at the left-top of the preview cell .
I've changed the relative position of the preview using transform: translate(-50%, -50%),so the cursor can be at the center on the preview while dragging.
But then I find the guide line doesn't fit along with the changed preview, it's still works according to the original position of the preview.
I've tried some 'offset' API on the docs but still can't work it out.
In this pic, I draw the red box, which is the original position of the preview, and the guide line works wrong
functions concerning the question are on below
const draggingPreview = () => {
const elt = document.createElement("div");
elt.style.width = '60px';
elt.style.height = '60px';
elt.style.transform = "translate(-50%,-50%)";
return elt;
};
const dropHandler = (graph, evt, dropCell, x, y) => {
const parent = graph.getDefaultParent();
this.graph.getModel().beginUpdate();
try {
let vertex = this.graph.insertVertex(
parent,
null,
null,
x - 30,
y - 30,
width,
height,
style
);
vertex.value = "xxxx";
} finally {
this.graph.getModel().endUpdate();
}
};
const ds = mxUtils.makeDraggable(
dom,
graph,
dropHandler,
draggingPreview(),
0,
0,
true,
true
);
ds.setGuidesEnabled(true);
EDIT : OK, It was my css page which had a rule on path, 'cause I use svg a lot. Removed that rule and the problem was gone !
I'm facing something pretty annoying and which I do not understand.
I'm using amChart to make a XY chart with multiple series. Not that hard.
The thing is, I can't customize my series ! Bullets and legend are ok, but not series.
Here's a screenshot for better understanding :
MyWeirdChart (new OP can't embed images, sorry)
As you can see I have my custom bullet pushed on my series and my legend is exactly what I want for my chart BUT series are staying unchanged.
Here is my JS draw function :
function drawChart(dateArray, casesArray, deathsArray, healedArray, hospitalizationsArray, reanimationsArray) {
am4core.useTheme(am4themes_animated);
var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.data = generateChartData(dateArray, casesArray, deathsArray, healedArray, hospitalizationsArray, reanimationsArray);
var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
function pushSeries(field, name, color) {
let series = chart.series.push(new am4charts.LineSeries());
series.dataFields.valueY = field;
series.dataFields.dateX = "date";
series.name = name;
series.tooltipText = name + ": [b]{valueY}[/]";
series.stroke = am4core.color(color);
series.strokeWidth = 3;
series.fill = am4core.color(color);
series.fillOpacity = 0.5;
let bullet = series.bullets.push(new am4charts.CircleBullet());
bullet.circle.stroke = am4core.color(color);
bullet.circle.strokeWidth = 2;
bullet.circle.fill = am4core.color(color);
bullet.circle.fillOpacity = 0.5;
bullet.circle.radius = 3;
}
pushSeries("cases", "Cas confirmés", "#32B3E3");
pushSeries("healed", "Guéris", "#00C750");
pushSeries("hospitalizations", "Hospitalisations", "#FFBB33");
pushSeries("reanimations", "Réanimations", "#FE3446");
pushSeries("deaths", "Morts", "black");
chart.cursor = new am4charts.XYCursor();
chart.scrollbarX = new am4core.Scrollbar();
chart.legend = new am4charts.Legend();
chart.cursor.maxTooltipDistance = 0;
}
Did I miss something ? I crawled forums and documentations and I'm now helpless.
My code is in my webpack app.js file. But I include amCharts with HTML scripts,
<script src="https://www.amcharts.com/lib/4/core.js"></script>
<script src="https://www.amcharts.com/lib/4/charts.js"></script>
<script src="https://www.amcharts.com/lib/4/themes/animated.js"></script>
not with webpack import. But I guess that if this was the problem, I would not be able to draw a chart at all.
OK, It was my css page which had a rule on path, 'cause I use svg a lot. Removed that rule and the problem was gone !
I have a menu that always has the same structure, but the IDs can change from one installation to another. the only thing that stays the same is the heading (in my case "Plugins"). I call the document.getElementsByClassName function with a Selector inside my test:
var slides = Selector(() =>{
return document.getElementsByClassName("c-p-header-text");
});
Every heading of an menu element has the c-p-header-text class. Here is what a menu heading element looks like:
<div id="ext-comp-1002" class="c-p c-tree c-p-collapsed" style="width: auto;">
<div class="c-p-header c-unselectable c-accordion-hd" id="ext-gen135" style="cursor: pointer;">
<div class="c-tool c-tool-toggle" id="ext-gen140"> </div>
<img src="/backEnd/images/s.gif" class="c-p-inline-icon order"><span class="c-p-header-text" id="ext-gen150">Plugins</span>
</div>
It would be easy to use await t.click("#ext-gen150") but it is not safe that it is always this id.
here is what i tried:
await t
.click('#sites__db');
var slides = Selector(() =>{
return document.getElementsByClassName("c-p-header-text");
});
console.log("[DEBUG]" + slides);
console.log("[DEBUG] found " + slides.length + " elements");
for(var i = 0; i < slides.length; i++)
{
var txtOfCurrElem = slides.item(i).innerText;
console.log("[DEBUG "+ i +"] Text: " + txtOfCurrElem);
}
Running this test give me the following output:
[DEBUG]function __$$clientFunction$$() {
var testRun = builder.getBoundTestRun() || _testRunTracker2.default.resolveContextTestRun();
var callsite = (0, _getCallsite.getCallsiteForMethod)(builder.callsiteNames.execution);
var args = [];
// OPTIMIZATION: don't leak `arguments` object.
for (var i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}return builder._executeCommand(args, testRun, callsite);
}
[DEBUG] found 0 elements
The plan is to find the element (with the heading "Plugins") and then click on it when the test continuous.
You don't have to use document.getElementsByClassName in this case. You can just use CSS class selector instead:
var slides = Selector('.c-p-header-text');
You should use the count property when dealing with an array of Selectors. docs. Also, element properties, like exists, count, and DOM node state properties are Promisified, so when you use them not in t.expect, you should use the await keyword:
var count = await slides.length;
console.log("[DEBUG] found " + count + " elements");
for(var i = 0; i < count; i++)
{
var txtOfCurrElem = await slides.nth(i).innerText;
console.log("[DEBUG "+ i +"] Text: " + txtOfCurrElem);
}
I found a simple answer to my question. I use the .withText option to click on the Plugins element:
.click(Selector('span').withText("Plugins"))
Since this name is also unique, it is always the correct element that gets clicked. I do not know if it would have worked with the solution from #AndreyBelym if my site is not an extJS web application.
I created this jsfiddle.
A line i connecting two elements, and I want the line to stay connected to both elements no matter where they go.
I've sort of succeeded, but with one pretty obvious error. It keeps drawing new lines instead of redrawing the existing line. Please help me on how to make it update the line position instead.
var stage = new createjs.Stage("canvas");
createjs.Ticker.setFPS(60);
createjs.Ticker.addEventListener("tick", tick);
var arrDots = [];
var arrLines = [];
var circle1 = new createjs.Shape().set({
x: stage.canvas.width/2,
y: 50,
cursor: "pointer",
name:"target"
});
circle1.graphics.f(createjs.Graphics.getRGB(Math.random()*0xFFFFFF))
.dc(0,0,20);
stage.addChild(circle1);
arrDots.push(circle1);
var circle2 = new createjs.Shape().set({
x: stage.canvas.width/2,
y: stage.canvas.height - 50,
cursor: "pointer",
name:"target"
});
circle2.graphics.f(createjs.Graphics.getRGB(Math.random()*0xFFFFFF))
.dc(0,0,20);
stage.addChild(circle2);
arrDots.push(circle2);
var line = new createjs.Shape().set({
graphics: new createjs.Graphics().s("#00f").mt(arrDots[0].x,
arrDots[0].y).lt(arrDots[1].x, arrDots[1].y)
});
stage.addChild(line);
arrLines.push([arrDots[0], arrDots[1], line]);
createjs.Tween.get(circle1, {loop: true}).to({x:50},
3000).to({x:stage.canvas.width/2}, 3000);
function tick(event) {
keepLineConnection();
stage.update();
}
function keepLineConnection() {
for(var i = 0; i < arrLines.length; i++) {
arrLines[i][2].graphics.mt(arrLines[i][0].x, arrLines[i][0].y).lt(arrLines[i][1].x, arrLines[i][1].y);
}
}
The reason it keeps drawing is because you keep adding commmands to the graphics. Basically, you are doing this:
graphics.mt().lt().mt().lt().mt().lt().mt().etc();
Since you are just adding new instrucitons, they will pile up over time,
and will eventually kill your processor.
An easy fix for that is to clear the graphics first before adding new ones:
graphics.clear().mt().lt();
A better approach is to use commands. Since EaselJS 0.7.0, all graphics commands are objects, and at any time you can update properties of those objects directly. For example, the MoveTo and LineTo commands both have an x and y property. Here is more info on Commands: http://blog.createjs.com/update-width-height-in-easeljs/
Here is a modified fiddle that stores of commands on the line, and then updates them on tick. I also made a few other updates, such as changing the timing mode to RAF, which is smoother than using interval-based timers at 60FPS.
https://jsfiddle.net/tck7x8u2/
// Store commands:
line.cmd1 = line.graphics.mt(0,0).command;
line.cmd2 = line.graphics.lt(0,0).command;
// Update commands:
var instr = arrLines[i],
line = instr[2];
line.cmd1.x = instr[0].x;
line.cmd1.y = instr[0].y;
line.cmd2.x = instr[1].x;
line.cmd2.y = instr[1].y;
Cheers!
Edit: Here is are some demos using that idea that I made a while back:
https://lab.gskinner.com/connections
http://jsfiddle.net/lannymcnie/2xoL08bx/
http://jsfiddle.net/lannymcnie/6rh7P/
I had defined an imageview in my layout for the individual items of a list, and they were set invisible. When I clicked a button, they will be show,but I can't get this action act. I want to achieve this effect. Here is my code:
//file:list_view_test.jade
Alloy
Window#win
Button#btn(title = "Show" onClick = "show_the_image_view")
ListView#list_view(defaultItemTemplate = "list_style")
Templates
ItemTemplate(name = "list_style")
View#item_view(bindId = "bind_item_view")
ImageView#image_view(bindId = "bind_image_view")
ListSection
ListItem(bind_item_view:backgroundImage = "/images/backgroundImage_1.png"
bind_image_view:image = "/images/unchecked_image.png")
ListItem(bind_item_view:backgroundImage = "/images/backgroundImage_2.png"
bind_image_view:image = "/images/unchecked_image.png")
//file:list_view_test.stss
#item_view{
width:100%;
height:10%
}
#image_view{
top:0;
left:0;
width:20%;
height:20%;
visible:false
}
//file:list_view_test.coffee
show_the_image_view = ->
if "Show" == $.btn.getTitle()
$.btn.setTitle("Hide")
//$.image_view.setVisible(true) (this code had been commented, cause it's wrong)
else if "Hide" == $.btn.getTitle()
$.btn.setTitle("Show")
//$.image_view.setVisible(false) (this code had been commented, cause it's wrong)
$.list_view.addEventListener('itemclick', = (e) ->
if e.itemIndex == 0
//$.image_view.setImage('/images/checked_image.png') (this code had been commented, cause it's wrong)
else if e.itemIndex == 1
//$.image_view.setImage('/images/checked_image.png') (this code had been commented, cause it's wrong)
Is there anyone who has a good method to solve the problem?